/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip.dns;
import com.ericsson.ssa.sip.SipFactoryImpl;
import com.ericsson.ssa.sip.SipURIImpl;
import com.ericsson.ssa.sip.UriUtil;
import com.ericsson.ssa.sip.UriUtil.UriUtilException;
import org.glassfish.comms.api.telurl.TelUrlResolver;
import org.glassfish.comms.api.telurl.TelUrlResolverException;
import org.glassfish.comms.api.uriutils.UriTools;
import org.jvnet.glassfish.comms.util.LogUtil;
import org.xbill.DNS.AAAARecord;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.Cache;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.NAPTRRecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipURI;
import javax.servlet.sip.TelURL;
import javax.servlet.sip.URI;
/**
* DNS resolver.
*
* @reviewed qmigkra 2006-oct-12
* @reviewed ejoelbi 2006-nov-07
*/
/**
* @reviewed qmaghes 2007-mars-21
*/
public class DnsResolver implements TelUrlResolver, UriTools {
private static final Logger logger = LogUtil.SIP_LOGGER.getLogger();
protected static DnsResolver myInstance = null;
private Random myRandomInstance = new java.util.Random();
private TargetFailedRegister myFailedTargets = new TargetFailedRegister();
private String myEnumTopDomain = "e164.arpa"; // this can be overidden by
private Translator translator;
private ConfigurationHandler configurationHandler;
private final ThreadLocal<List<TargetTuple>> threadLocalFailedRegister = new ThreadLocal<List<TargetTuple>>();
// preferences or JMX
public DnsResolver() {
translator = new Translator();
configurationHandler = new ConfigurationHandler(translator);
}
public static synchronized DnsResolver getInstance() {
if (myInstance == null) {
myInstance = new DnsResolver();
}
return myInstance;
}
public String normalize(String localPhoneNumber, String phoneContext) {
return translator.normalize(localPhoneNumber,
phoneContext);
}
public URI canonicalize(URI uri) {
URI canonicalizedUri = translator.canonicalize(uri);
return (canonicalizedUri != null) ? canonicalizedUri : uri;
}
public void setTargetFailed(TargetTuple target, int expireValue) {
myFailedTargets.registerFailed(target, expireValue);
}
public boolean isTargetFailed(TargetTuple target) {
List<TargetTuple> localRegister = threadLocalFailedRegister.get();
if (localRegister != null && localRegister.contains(target)) {
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "skipping target in thread local set " + target);
}
return true;
}
return myFailedTargets.isFailed(target);
}
public void setThreadLocalFailedTargets(List<TargetTuple> failedTargets) {
threadLocalFailedRegister.set(failedTargets);
}
public void clearThreadLocalFailedTargets() {
threadLocalFailedRegister.set(null);
}
public TargetTuple lookupNameFromSRV(SRVRecord record,
SipTransports theProtocol)
throws DnsLookupFailedException, SrvPrioLevelNoValidIpException {
// orginal
// TargetTuple.createFromSrv(srv, theProtocol);
// lookup corresponding A-records
String srvTarget = record.getTarget().toString(); // String mySRVDomain =
// record.getTarget().toString();
// check if srv target is numeric instead of an domain
if (TargetResolver.isNumericIp(srvTarget)) {
// the srv record target is an ipadress which has failed
// lets return a null target (which means that default values might be
// used
// for "Selecting SIP Servers".
// TODO check if an exception should be thrown to the
// transport layer
TargetTuple tuple = new TargetTuple(theProtocol, srvTarget,
record.getPort());
if (isTargetFailed(tuple)) {
return null;
}
return tuple;
}
String[] ips = lookupNameRecords(srvTarget);
// first take care of the most frequent (?) case with only 1 A record
// assigned to the SRV record
if ((ips.length == 1)) {
TargetTuple tuple = new TargetTuple(theProtocol, ips[0],
record.getPort());
if (isTargetFailed(tuple)) {
return null;
}
return tuple;
}
/*
* add randomization to distribute among A-records (load balance) however
* to avoid a possibly INFINITE loop make maximum ips.length attempts to
* find a suitable target which has not failed otherwise test records
* sequentially
*/
int randomIndexToUse = 0;
int attempts = 0;
while ((attempts < (ips.length))) {
attempts++;
// use a random index (which is not round-robin but which distributes
// sufficiently)
randomIndexToUse = getRandomIndex(ips.length);
String ip = ips[randomIndexToUse];
TargetTuple tuple = new TargetTuple(theProtocol, ip,
record.getPort());
if (isTargetFailed(tuple) == false) {
return tuple;
}
}
// did not find a record by random which hasent failed...
// Lets test records sequentially
for (int i = 0; i < ips.length; i++) {
TargetTuple tuple = new TargetTuple(theProtocol, ips[i],
record.getPort());
if (isTargetFailed(tuple) == false) {
return tuple;
}
}
throw new SrvPrioLevelNoValidIpException(
"found no valid ip adress for this srv record:" + srvTarget);
}
public Record[] doLookup(String domainNameToLookup, int type)
throws DnsLookupFailedException {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"doLookup: " + domainNameToLookup + " " + Type.string(type));
logger.log(Level.FINE,
"current #cacheentries: " +
Lookup.getDefaultCache(DClass.IN).getSize());
}
// domain need to be fully qualified with new dnsjava version
if (domainNameToLookup.charAt(domainNameToLookup.length() - 1) != '.') {
domainNameToLookup += ".";
}
Lookup lkup = null;
try {
lkup = new Lookup(domainNameToLookup, type);
} catch (TextParseException e) {
// we wants only one "checked" exception, lets wrap into a
// DnsLookupFailedException
throw new DnsLookupFailedException("Failed to lookup domain:" +
domainNameToLookup + " error:" + e.getMessage());
}
Record[] records = lkup.run();
int res = lkup.getResult();
if (res == Lookup.TRY_AGAIN) {
throw new DnsServerUnavailableException(lkup.getErrorString());
} else if (lkup.getResult() != Lookup.SUCCESSFUL) {
throw new DnsLookupFailedException("no such domain:" +
domainNameToLookup + " error:" + lkup.getErrorString());
}
return records;
}
public TargetTuple lookupSRVRecord(SipTransports theProtocol,
String domainNameToLookup) {
try {
Record[] records = doLookup(domainNameToLookup, Type.SRV);
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"number of DNS/SRV records:" + records.length);
}
// 1) sort on prio, weight
java.util.Arrays.sort(records, new SrvComparator());
// 2) calculate runningSum
int[] runningSum = new int[records.length];
int deltaSum = 0;
int numPriorityGroups = 0;
int[] priorityGroupBoundaries = new int[records.length];
int lastPrio = -1;
int prioIndex = 0;
for (int i = 0; i < records.length; i++) {
SRVRecord srv = (SRVRecord) records[i];
if (srv.getPriority() != lastPrio) {
lastPrio = srv.getPriority();
deltaSum = 0;
priorityGroupBoundaries[prioIndex] = i;
prioIndex++;
numPriorityGroups++;
}
deltaSum += srv.getWeight();
runningSum[i] = deltaSum;
//
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"SRVRecord.toString():" + srv.toString());
}
/*
* logger.log(Level.FINE, "SRVRecord.toString():" + srv.toString());
* //logger.log(Level.FINE, "Host " + srv.getTarget());
* logger.log(Level.FINE, "Priority:"+ srv.getPriority()); logger.log(Level.FINE, "
* Weight:"+ srv.getWeight()); logger.log(Level.FINE, " runningSum:"+
* runningSum[i]);
*/
}
for (prioIndex = 0; prioIndex < numPriorityGroups; prioIndex++) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "SRV priolevel:" + prioIndex);
}
try {
return lookupSRVPrioLevel(prioIndex, theProtocol,
runningSum, records, numPriorityGroups,
priorityGroupBoundaries);
} catch (SrvPrioLevelNoValidIpException noValidIPExc) {
continue;
}
}
}
//
catch (DnsLookupFailedException dLookupEx) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, dLookupEx.getMessage());
}
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"DNS/SRV No record found: " + domainNameToLookup);
}
return null;
}
public TargetTuple lookupSRVPrioLevel(int prioIndex,
SipTransports theProtocol, int[] runningSum, Record[] records,
int numPriorityGroups, int[] priorityGroupBoundaries)
throws DnsLookupFailedException, SrvPrioLevelNoValidIpException {
int firstIndex = priorityGroupBoundaries[prioIndex];
int lastIndex = ((prioIndex + 1) < numPriorityGroups)
? (priorityGroupBoundaries[prioIndex + 1] - 1) : (records.length -
1);
int maxValue = runningSum[lastIndex] + 1;
int testValue = getRandomIndex(maxValue);
int ignoreIndex = -1;
for (int i = firstIndex; i < (lastIndex + 1); i++) {
SRVRecord srv = (SRVRecord) records[i];
// logger.log(Level.FINE, "SRVRecord.toString():" + srv.toString());
if (runningSum[i] >= testValue) {
// this is it
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "found srv:" + srv.toString());
}
TargetTuple targetTuple =
lookupNameFromSRV(srv, theProtocol);
if(targetTuple != null){
return targetTuple;
}
else{
ignoreIndex = i;
}
}
}
//Since selective lookup failed, iterate over complete list
for (int i = firstIndex; i < (lastIndex + 1); i++) {
if(i == ignoreIndex){
continue;
}
SRVRecord srv = (SRVRecord) records[i];
TargetTuple targetTuple =
lookupNameFromSRV(srv, theProtocol);
if(targetTuple != null){
return targetTuple;
}
}
throw new SrvPrioLevelNoValidIpException(
"found no valid ip adress for records with priority "
+ prioIndex);
}
//
public TargetTuple lookupSRVDirect(SipTransports protocol,
String domainNameToLookup) throws DnsLookupFailedException {
return lookupSRVDirect(protocol, domainNameToLookup, false);
}
public TargetTuple lookupSRVDirect(SipTransports protocol,
String domainNameToLookup, boolean isUdpMTUExceeded)
throws DnsLookupFailedException {
if (isUdpMTUExceeded && (protocol == SipTransports.UDP_PROT)) {
protocol = SipTransports.TCP_PROT;
}
try {
switch (protocol.ordinal()) {
case SipTransports.TCP:
case SipTransports.UDP:
return lookupSRVRecord(protocol,
getSrvDirectLookupId(protocol, domainNameToLookup));
case SipTransports.UNDEFINED:default: {
TargetTuple target = null;
// first try with UDP then TCP if protocol is undefined.
// we MAY try the protocols we support in any order RFC3263
// Section
// 4.1
if ((isUdpMTUExceeded == false) &&
((target = lookupSRVDirect(SipTransports.UDP_PROT,
domainNameToLookup)) != null)) {
} else if ((target = lookupSRVDirect(SipTransports.TCP_PROT,
domainNameToLookup)) != null) {
}
return target;
}
}
} catch (DnsLookupFailedException dnfe) {
return null;
}
}
private String getSrvDirectLookupId(SipTransports protocol,
String domainNameToLookup) throws DnsLookupFailedException {
String lookupStr = protocol.getSRVToken() + "." + domainNameToLookup;
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "getDirectSrvLookupString:" + lookupStr);
}
return lookupStr;
}
public void clearLocalCache() {
Cache cache = Lookup.getDefaultCache(DClass.IN);
cache.clearCache();
}
public String lookupName(String domainNameToLookup)
throws Exception {
String ip;
if ((ip = lookupARecord(domainNameToLookup)) != null) {
return ip;
} else if ((ip = lookupAAAARecord(domainNameToLookup)) != null) {
return ip;
} else {
return null;
}
}
public String[] lookupNameRecords(String domainNameToLookup)
throws DnsLookupFailedException {
String[] ips = null;
if ((ips = lookupARecords(domainNameToLookup)) != null) {
return ips;
} else if ((ips = lookupAAAARecords(domainNameToLookup)) != null) {
return ips;
} else {
return null;
}
}
public String lookupARecord(String domainNameToLookup)
throws DnsLookupFailedException {
String[] ips = lookupARecords(domainNameToLookup);
if (ips == null) {
return null;
}
int indexToUse = 0;
if ((ips.length > 1)) {
// we need only to distribute lookups when we have at least 2 A-records
//
// use a random index (which is not round-robin but which distributes
// sufficiently)
indexToUse = getRandomIndex(ips.length);
}
return ips[indexToUse];
}
public String[] lookupAAAARecords(String domainNameToLookup)
throws DnsLookupFailedException {
try {
Record[] records = doLookup(domainNameToLookup, Type.AAAA);
String[] ips = new String[records.length];
for (int i = 0; i < records.length; i++)
ips[i] = ((AAAARecord) records[i]).getAddress().getHostAddress();
return ips;
} catch (DnsLookupFailedException dLookupEx) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, dLookupEx.getMessage());
}
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"DNS/A No record found: " + domainNameToLookup);
}
return null;
}
public String[] lookupARecords(String domainNameToLookup)
throws DnsLookupFailedException {
try {
Record[] records = doLookup(domainNameToLookup, Type.A);
String[] ips = new String[records.length];
for (int i = 0; i < records.length; i++) //
{
ips[i] = ((ARecord) records[i]).getAddress().getHostAddress();
}
return ips;
} catch (DnsLookupFailedException dLookupEx) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, dLookupEx.getMessage());
}
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"DNS/A No record found: " + domainNameToLookup);
}
return null;
}
public String lookupAAAARecord(String domainNameToLookup)
throws DnsLookupFailedException {
try {
Record[] records = doLookup(domainNameToLookup, Type.AAAA);
int indexToUse = 0;
if ((records.length > 1)) {
// we need only to distribute lookups when we have at least 2
// A-records
//
// use a random index (which is not round-robin but which
// distributes sufficiently)
indexToUse = getRandomIndex(records.length);
}
return ((AAAARecord) records[indexToUse]).getAddress().getHostAddress();
} catch (DnsLookupFailedException dLookupEx) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, dLookupEx.getMessage());
}
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"DNS/AAAA No record found: " + domainNameToLookup);
}
return null;
}
private int getRandomIndex(int upperIndex) {
int indexToUse = myRandomInstance.nextInt(upperIndex);
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"Picked a random value between 0 and:" + upperIndex +
" (excl). Random:" + indexToUse);
}
return indexToUse;
}
public TargetTuple lookupNAPTRRecord(String domainNameToLookup,
boolean isUdpMTUExceeded) {
try {
Record[] records = doLookup(domainNameToLookup, Type.NAPTR);
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"number of DNS/NAPTR records:" + records.length);
}
java.util.Arrays.sort(records, new NaptrComparator());
// TODO NAPTR: Use the first record we support.
// from where do we know which protocol this server supports/prefers?
// NAPTR lookup on this host?
// (but only within the implemented set (UDP, TCP)
// Could we assume allways having NAPTR records for own host or
// should we have an fallback in a "local" config file
//
// should we consider other protocol for loadbalancing/fallback
// --> probably NO
// I.e. when the protocol to use is decided via NAPTR then we stick
// with that protocol
// only exception is MTU size > 1300 bytes etc.
//
for (int i = 0; i < records.length; i++) {
NAPTRRecord record = (NAPTRRecord) records[i];
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"NAPTRRecord.toString():" + record.toString());
}
String service = record.getService();
// Lets check the NAPTR record. Do we support the protocol?
// if MTUExceeded is true UDP should not be considered
if (SipTransports.UDP_PROT.isSupported() &&
service.equals(SipTransports.UDP_PROT.getNAPTRId()) &&
(isUdpMTUExceeded == false)) {
return lookupSRVRecord(SipTransports.UDP_PROT,
record.getReplacement().toString());
} else if (SipTransports.TCP_PROT.isSupported() &&
service.equals(SipTransports.TCP_PROT.getNAPTRId())) {
return lookupSRVRecord(SipTransports.TCP_PROT,
record.getReplacement().toString());
}
}
} catch (DnsLookupFailedException dLookupEx) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, dLookupEx.getMessage());
}
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"DNS/NAPTR No record found: " + domainNameToLookup);
}
return null;
}
/*
* This is the method which implements the interface TelUrlResolver This
* class maps DnsServerUnavailableException to a IOException
*/
public SipURI lookupSipURI(URI uri)
throws TelUrlResolverException, IOException {
try {
return doLookupSipURI(uri);
} catch (DnsServerUnavailableException e) {
throw new IOException(e.getMessage());
}
}
public boolean isTelephoneNumber(URI uri) {
return UriUtil.isTelephoneNumber(uri);
}
protected SipURI doLookupSipURI(URI uri) throws TelUrlResolverException {
// validate uri
if (!isTelephoneNumber(uri)) {
throw new TelUrlResolverException("The uri is not a phone number:" +
uri);
}
TelURL telUrl = null;
if (uri.isSipURI()) {
try {
telUrl = UriUtil.convertToTelURL((SipURI) uri);
} catch (UriUtilException e) {
throw new TelUrlResolverException("Could not convert URI: \"" +
uri + "\" to Tel-URL", e);
}
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST,
"Sip-URI was converted to Tel-URL: " + telUrl);
}
} else if (uri.getScheme().equals(SipFactoryImpl.TEL_URI_PROTOCOL)) {
telUrl = (TelURL) uri;
}
String phoneNumber;
if (telUrl.isGlobal()) {
phoneNumber = telUrl.getPhoneNumber();
} else {
String phoneContext;
if ((phoneContext = telUrl.getPhoneContext()) == null) {
throw new TelUrlResolverException("The local number is missing a phone-context: "+telUrl);
} else {
phoneNumber = normalize(telUrl.getPhoneNumber(), phoneContext);
if (phoneNumber == null) {
throw new TelUrlResolverException("Could not normalize the phone number: "+telUrl);
}
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST,
"The number in the Tel-URL: " + telUrl +
" was normalized to " + phoneNumber);
}
}
}
try {
String AUS = EnumUtil.getAUSValue(phoneNumber);
String domainNameToLookup = EnumUtil.toDomain(AUS, myEnumTopDomain);
return lookupTelUrlNAPTRRecord(AUS, domainNameToLookup,
new HashSet<String>(), 1);
} catch (DnsServerUnavailableException dnsue) {
// All runtime exceptions except DnsServerUnavailableException
// should be wrapped into a TelUrlResolverException
throw dnsue;
} catch (RuntimeException rte) {
throw new TelUrlResolverException(rte);
}
}
/**
* @param AUS
* @param e164arpa_domain
* @param visited
* @param depth
* @return
*/
protected SipURI lookupTelUrlNAPTRRecord(String AUS,
String e164arpa_domain, Set<String> visited, int depth)
throws TelUrlResolverException {
if ((depth > EnumUtil.MAX_DEPTH) || !visited.add(e164arpa_domain)) {
throw new TelUrlResolverException("Loop detected when resolving:" +
AUS);
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"depth:" + depth + " AUS:" + AUS + " domain:" +
e164arpa_domain);
}
try {
Record[] records = doLookup(e164arpa_domain, Type.NAPTR);
Arrays.sort(records, new NaptrComparator());
for (Record record : records) {
NAPTRRecord naptrRecord = (NAPTRRecord) record;
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"number of DNS/NAPTR records:" + records.length);
logger.log(Level.FINE,
"NAPTRRecord.toString():" + record.toString());
}
String flag = naptrRecord.getFlags();
String service = naptrRecord.getService();
Name replacement = naptrRecord.getReplacement();
if (service.equalsIgnoreCase("E2U+sip") ||
service.equalsIgnoreCase("sip+E2U")) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"flag:" + naptrRecord.getFlags() + " flaglength:" +
naptrRecord.getFlags().length());
logger.log(Level.FINE,
"regexp:" + naptrRecord.getRegexp() +
" replacement:" + replacement);
}
if (!EnumUtil.isEmpty(replacement) && (flag.length() == 0)) {
return lookupTelUrlNAPTRRecord(AUS,
replacement.toString(), visited, ++depth);
}
String substitution = EnumUtil.applyRegExp(AUS,
naptrRecord.getRegexp());
if (substitution == null) {
// try next record
continue;
}
if (flag.equals("u")) {
int separator = substitution.indexOf(':');
if (separator == -1) {
throw new TelUrlResolverException(
"The regexp substitution result is not any supported uri:" +
substitution);
}
String schemePart = substitution.substring(0, separator);
String theUriPart = substitution.substring(separator +
1);
if (schemePart.equals(SipFactoryImpl.TEL_URI_PROTOCOL)) {
return lookupTelUrlNAPTRRecord(AUS,
EnumUtil.toDomain(theUriPart, myEnumTopDomain),
visited, ++depth);
} else if (schemePart.equals(
SipFactoryImpl.SIP_URI_PROTOCOL) ||
schemePart.equals(
SipFactoryImpl.SIPS_URI_PROTOCOL)) {
try {
SipURIImpl sipuri = new SipURIImpl(schemePart,
theUriPart, 0);
// check user=phone etc here
String userParam = sipuri.getParameter("user");
if ((userParam != null) &&
userParam.equals("phone")) {
String userTelUrl = sipuri.getUser();
return lookupTelUrlNAPTRRecord(AUS,
EnumUtil.toDomain(userTelUrl,
myEnumTopDomain), visited, ++depth);
}
return sipuri;
} catch (ServletParseException e) {
throw new TelUrlResolverException(e);
}
} else {
throw new TelUrlResolverException(
"The regexp substitution result is not any supported uri:" +
substitution);
}
} else if (flag.length() == 0) {
return lookupTelUrlNAPTRRecord(AUS, substitution,
visited, ++depth);
}
/* else ignore record */
}
/* else ignore record */
}
} catch (DnsLookupFailedException dLookupEx) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, dLookupEx.getMessage());
}
}
return null;
}
public void setEnumTopDomain(String topDomain) {
myEnumTopDomain = topDomain;
}
public String getEnumTopDomain() {
return myEnumTopDomain;
}
public void setDnsCacheSize(int newSize) {
Cache cache = Lookup.getDefaultCache(DClass.IN);
synchronized (cache) {
cache.setMaxEntries(newSize);
}
}
}