/*
* 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.container;
import com.ericsson.ssa.config.Config;
import com.ericsson.ssa.config.ConfigFactory;
import com.ericsson.ssa.config.Constants;
import com.ericsson.ssa.config.event.ConfigAddEvent;
import com.ericsson.ssa.config.event.ConfigChangeListener;
import com.ericsson.ssa.config.event.ConfigRemoveEvent;
import com.ericsson.ssa.config.event.ConfigUpdateEvent;
import com.ericsson.ssa.sip.SipURIImpl;
import com.ericsson.ssa.sip.dns.SipTransports;
import com.ericsson.ssa.sip.dns.TargetTuple;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import org.jvnet.glassfish.comms.util.LogUtil;
import java.util.logging.Logger;
import javax.servlet.sip.SipURI;
/**
*
* @author ELNELBO
*/
public class SipBindingResolver {
/*
* A lot to tricky things still to resolve.
* - Multithreading, Initialization, multiple users and the Config event thread.
* - Transaction awareness of the ConfigEvent (add node, but prefs not yet set, but event sent)
* - Expects valid prefs with defaults set.
*/
private static final SipBindingResolver INSTANCE = new SipBindingResolver();
private static final String CTX_PARENT = "/SipService/SipListener";
private static final String CTX_PARENT_REGEXP = "/SipService/SipListener";
private static final String CTX_REGEXP = "/SipService/SipListener/([^/]+)";
private static final String SIP_CONTAINER = "/SipContainer";
/** The context to be used for obtaining a lease for the public binding.
*/
public static final String PUBLIC_BINDING_CTX = "PUBLIC_BINDING_CTX";
private Config config = ConfigFactory.getConfig();
private Logger log = LogUtil.SIP_LOGGER.getLogger();
private ParentCtxChangeListener parentCtxListener = new ParentCtxChangeListener();
private PublicCtxChangeListener publicCtxListener = new PublicCtxChangeListener();
// all local listener addresses that are not internal
private Map<String, SipBindingCtx> localcontexts = new HashMap<String, SipBindingCtx>();
// all external addresses in listener as well as sip container
private Map<String, SipBindingCtx> publiccontexts = new HashMap<String, SipBindingCtx>();
// all internal addresses to be used only by clb
private Map<String, SipBindingCtx> privatecontexts = new HashMap<String, SipBindingCtx>();
private Map<String, CtxChangeListener> ctxListeners = new HashMap<String, CtxChangeListener>();
private List<SipBindingListener> sipBindingListeners = new ArrayList<SipBindingListener>();
private String currentPublicHost = null;
private Random rand = new Random();
private static Set<SipURIImpl> outboundInterfaces = new LinkedHashSet<SipURIImpl>(6);
/** Creates a new instance of SipBindingResolver */
public SipBindingResolver() {
}
public static SipBindingResolver instance() {
return INSTANCE;
}
public void init() {
ConfigFactory.instance()
.registerConfigChangeListener(CTX_REGEXP, parentCtxListener);
//Init the local bindings confgured
for (String childName : config.getChildNames(CTX_PARENT)) {
String ctx = getCtxForName(childName);
updateContexts(ctx);
CtxChangeListener ctxListener = new CtxChangeListener();
ConfigFactory.instance()
.registerConfigChangeListener(getCtxRegExp(ctx), ctxListener);
ConfigFactory.instance()
.registerConfigChangeListener(getCtxSslRegExp(ctx), ctxListener);
}
ConfigFactory.instance()
.registerConfigChangeListener(SIP_CONTAINER, publicCtxListener);
publiccontexts.put(PUBLIC_BINDING_CTX,
new SipBindingCtx(this, PUBLIC_BINDING_CTX, resolvePublicTargetTuples(), false));
setInterfaces();
}
/*
* Adds the internal tuple to the pirvate contexts
*/
private void addInternal(String ctx) {
TargetTuple[] tts = resolveTargetTuples(ctx, true);
TargetTuple[] newtts = new TargetTuple[tts.length - 1];
int i = 0;
for (TargetTuple tt : tts) {
if (tt.getProtocol() == SipTransports.TCP_PROT) {
newtts[i++] = tt;
}
}
privatecontexts.put(ctx, new SipBindingCtx(this, ctx, newtts));
}
private void addExternal(String ctx) {
TargetTuple[] tts = resolveTargetTuples(ctx, false);
if (tts != null) {
publiccontexts.put(ctx, new SipBindingCtx(this, ctx, tts));
}
}
/*
* Utility method to update the context cache.
*/
private void updateContexts(String ctx) {
SipBindingCtx localctx = new SipBindingCtx(this, ctx,
resolveTargetTuples(ctx, true));
if (localctx.isExternal()) {
localcontexts.put(ctx, localctx);
addExternal(ctx);
} else if (localctx.isInternal()) {
addInternal(ctx);
} else {
localcontexts.put(ctx, localctx);
addExternal(ctx);
addInternal(ctx);
}
}
/*
* Returns all the contexts for which the network manager
* has to open up ports.
*/
public String [] getContexts(){
List<String> ctxs = new ArrayList<String>(localcontexts.keySet());
List<String> ctxs1 = new ArrayList<String>(privatecontexts.keySet());
// add only if the internal listener is not already present in local
// this is to ensure that default listeners work properly
for (String ctx : ctxs1){
if (localcontexts.get(ctx) == null){
ctxs.add(ctx);
}
}
return ctxs.toArray(new String[ctxs.size()]);
}
/*
* All listener addresses
*/
public String[] getLocalContexts() {
List<String> ctxs = new ArrayList<String>(localcontexts.keySet());
return ctxs.toArray(new String[ctxs.size()]);
}
/*
* All listener external addresses, typically this returns all the contexts
* that have external-address configured, which is typically the ip sprayer
* address.
*/
public String[] getPublicContexts() {
List<String> ctxs = new ArrayList<String>(publiccontexts.keySet());
return ctxs.toArray(new String[ctxs.size()]);
}
public String[] getPrivateContexts() {
List<String> ctxs = new ArrayList<String>(privatecontexts.keySet());
return ctxs.toArray(new String[ctxs.size()]);
}
public SipBindingCtx getContext(String ctx){
SipBindingCtx bindingctx = getLocalContext(ctx);
if (bindingctx == null){
bindingctx = getPrivateContext(ctx);
}
return bindingctx;
}
public SipBindingCtx getLocalContext(String ctx) {
SipBindingCtx sipBindingCtx = localcontexts.get(ctx);
return sipBindingCtx;
}
public SipBindingCtx getPublicContext(String ctx) {
SipBindingCtx sipBindingCtx = publiccontexts.get(ctx);
return sipBindingCtx;
}
public SipBindingCtx getPrivateContext(String ctx) {
SipBindingCtx sipBindingCtx = privatecontexts.get(ctx);
return sipBindingCtx;
}
public boolean isStale(SipBindingCtx sipBindingCtx) {
if (sipBindingCtx==null) {
return true;
}
if (sipBindingCtx.isInternal()){
return !privatecontexts.containsKey(sipBindingCtx.getContext()) ||
privatecontexts.get(sipBindingCtx.getContext()) !=sipBindingCtx;
} else {
return !localcontexts.containsKey(sipBindingCtx.getContext()) ||
localcontexts.get(sipBindingCtx.getContext()) !=sipBindingCtx;
}
}
//utils
public String getCurrentPublicHost() {
if (currentPublicHost==null) {
currentPublicHost =
publiccontexts.get(PUBLIC_BINDING_CTX).getTargetTuples()[0].getIP();
}
return currentPublicHost;
}
public SipBindingCtx getActiveContext(SipTransports protocol, Map<String,
SipBindingCtx> contexts) {
SipBindingCtx ctx = null;
List<SipBindingCtx> ctxs = getContextsForProtocol(protocol, contexts);
if (!ctxs.isEmpty()) {
ctx = ctxs.get(rand.nextInt(ctxs.size()));
}
return ctx;
}
/**
* Get an active SipBindingCtx for a specific protocol.
*
* @param protocol
* @return SipBindingCtx
*/
public SipBindingCtx getActiveLocalContext(SipTransports protocol) {
return getActiveContext(protocol, localcontexts);
}
/**
* Get an active SipBindingCtx for a specific protocol.
*
* @param protocol
* @return SipBindingCtx
*/
public SipBindingCtx getActiveInternalContext(SipTransports protocol) {
return getActiveContext(protocol, privatecontexts);
}
public List<SipBindingCtx> getContextsForProtocol(SipTransports protocol,
Map<String, SipBindingCtx> contexts) {
List<SipBindingCtx> ctxs = new ArrayList<SipBindingCtx>(1);
Set <Entry<String, SipBindingCtx>> ctxset = null;
ctxset = contexts.entrySet();
for (Map.Entry<String, SipBindingCtx> e : ctxset) {
if (protocol == null ||
e.getValue().getTargetTupleForProtocol(protocol) != null) {
ctxs.add(e.getValue());
}
}
return ctxs;
}
public SipBindingCtx getActiveExternalContext(){
return publiccontexts.get(PUBLIC_BINDING_CTX);
}
//SipBindingListeners
public void registerSipBindingListener(SipBindingListener listener) {
synchronized(sipBindingListeners) {
sipBindingListeners.add(listener);
}
}
public void deregisterSipBindingListener(SipBindingListener listener) {
synchronized(sipBindingListeners) {
sipBindingListeners.remove(listener);
}
}
private void processNewSipBindingCtxAvalable(String context) {
synchronized(sipBindingListeners) {
for (SipBindingListener listener : sipBindingListeners) {
listener.newSipBindingCtxAvaliable(context);
}
}
}
private void processSipBindingCtxUpdated(String context) {
synchronized(sipBindingListeners) {
for (SipBindingListener listener : sipBindingListeners) {
listener.sipBindingCtxUpdated(context);
}
}
}
private void processPublicSipBindingCtxUpdated() {
synchronized(sipBindingListeners) {
for (SipBindingListener listener : sipBindingListeners) {
listener.publicSipBindingCtxUpdated();
}
}
}
private void processSipBindingCtxRemove(String context) {
synchronized(sipBindingListeners) {
for (SipBindingListener listener : sipBindingListeners) {
listener.sipBindingCtxRemoved(context);
}
}
}
//ConfigChangeListeners
private String getCtxForName(final String name) {
return CTX_PARENT + "/" + name;
}
private String getCtxRegExp(final String ctx) {
return ctx;
}
private String getCtxSslRegExp(final String ctx) {
return ctx+"/Ssl";
}
//Resolvement
private TargetTuple[] resolveTargetTuples(String ctx, boolean local) {
String address = null;
int port = 0;
if (local) {
address = resolveLocalAddress(config.get(ctx, "Address"));
port = resolveLocalPort(config.get(ctx, "Port"));
} else {
// check for empty
if ((config.get(ctx, "ExternalSipAddress") == null) ||
(resolveLocalAddress(config.get(ctx, "ExternalSipAddress")) == null)){
return null;
}
address = resolveLocalAddress(config.get(ctx, "ExternalSipAddress"));
port = resolveLocalPort(config.get(ctx, "ExternalSipPort"));
}
String transport = config.get(ctx, "Transport");
List<SipTransports> transports = new ArrayList<SipTransports>();
for (String prot : transport.split("_")) {
try {
transports.add(SipTransports.getTransport(prot));
} catch (Exception ex) {
//TODO logging!
throw new IllegalArgumentException(ex);
}
}
TargetTuple[] targetTuples = new TargetTuple[transports.size()];
int i = 0;
for (SipTransports st : transports) {
targetTuples[i++] = new TargetTuple(st, address, port);
}
return targetTuples;
}
private String resolveLocalAddress(String anLocalAddress) {
String address = ((anLocalAddress != null) &&
(anLocalAddress.length() > 0)) ? anLocalAddress
: Constants.BIND_TO_ANY;
return address;
}
private int resolveLocalPort(String aLocalPort) {
int port = ((aLocalPort != null) && (aLocalPort.length() > 0))
? Integer.parseInt(aLocalPort)
: Integer.parseInt(Constants.DEFAULT_SIP_PORT);
return port;
}
private TargetTuple[] resolvePublicTargetTuples() {
String address = resolvePublicAddress(config.get(SIP_CONTAINER,
"ExternalAddress"));
int sipPort = resolvePublicPort(config.get(SIP_CONTAINER, "ExternalSipPort"),
Constants.DEFAULT_SIP_PORT);
int sipsPort = resolvePublicPort(config.get(SIP_CONTAINER, "ExternalSipsPort"),
Constants.DEFAULT_SIPS_PORT);
TargetTuple[] targetTuples = {
new TargetTuple(SipTransports.UDP_PROT, address, sipPort),
new TargetTuple(SipTransports.TCP_PROT, address, sipPort),
new TargetTuple(SipTransports.TLS_PROT, address, sipsPort)
};
return targetTuples;
}
private String resolvePublicAddress(String anPublicAddress) {
String address = ((anPublicAddress != null) &&
(anPublicAddress.length() > 0)) ? anPublicAddress : getLanAddress();
return address;
}
private int resolvePublicPort(String aPublicPort, String defaultPort) {
int port = ((aPublicPort != null) && (aPublicPort.length() > 0))
? Integer.parseInt(aPublicPort)
: Integer.parseInt(defaultPort);
return port;
}
/**
* getLanAddress() tries to find a configured IPv4/IPv6 address of a physical
* network interface. Some heuristics will be applied so that the
* externally most visible address will most likely be returned. <br>
* getLanAddress() always returns a correctly formatted dotted-decimal IP
* address string; in the event of a machine with no configured IP addresses
* it will return "0.0.0.0". <br>
*
* @return java.lang.String
* @author erarafo
*/
private String getLanAddress() {
String lanAddress = null;
// Fix for Issue 457 : Get the ip addresses of the configured sip listener prefering TLS above UDP_TCP
List<SipBindingCtx> ctxs = getContextsForProtocol(SipTransports.TLS_PROT, localcontexts);
if (ctxs == null || ctxs.size() == 0) {
ctxs = getContextsForProtocol(SipTransports.TCP_PROT, localcontexts);
} else if (ctxs.size() == 1 && ctxs.get(0).getTargetTuples()[0].getAddress().isLoopbackAddress()) {
//Let UDP_TCP compete with TLS when TLS is only loopback
ctxs.addAll(getContextsForProtocol(SipTransports.TCP_PROT, localcontexts));
}
List<InetAddress> inetAddresses = new ArrayList<InetAddress>();
boolean foundANYAddress = false;
for (SipBindingCtx ctx: ctxs) {
InetAddress inet = null;
if (ctx.isEnabled() && !ctx.isInternal()) {
inet = ctx.getTargetTuples()[0].getAddress();
if (inet != null) {
if (inet.isAnyLocalAddress())
foundANYAddress = true;
else if (!inetAddresses.contains(inet))
inetAddresses.add(inet);
}
}
}
if (inetAddresses != null && inetAddresses.size() > 0){
lanAddress = inetAddresses.get(0).getHostAddress();
} else if (foundANYAddress) {
addNICInetAddresses(inetAddresses);
lanAddress = getBestAddress(inetAddresses);
}//Only when a ANY wildcard address is configured all NIC InetAddresses are taken into account
// if the user has desgintated the address as external, we do not need this
// in a lab configuration external addresses could be 10.*.*.*
if (lanAddress == null) {
lanAddress = Constants.BIND_TO_ANY;
if (log.isLoggable(Level.WARNING))
log.log(Level.WARNING, "No suitable IP address found using " + lanAddress );
}
if (isMultiHomed()) {
if (log.isLoggable(Level.WARNING))
log.log(Level.WARNING, "This is a multihomed machined, using the external address as "
+ lanAddress);
}
log.log(Level.INFO, "LanAddress: External Address not configured, using value '" + lanAddress + "'");
return lanAddress;
}
private boolean isMultiHomed() {
int count = 0;
try {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets)) {
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
if (!inetAddress.isLoopbackAddress())
count++;
}
}
} catch (Exception e) {
}
return (count>1?true:false);
}
private void addNICInetAddresses(List<InetAddress> inetAddresses) {
Enumeration<NetworkInterface> nifs = null;
String me = "NIC address resolve";
try {
nifs = NetworkInterface.getNetworkInterfaces();
} catch (SocketException se) {
if (log.isLoggable(Level.WARNING)) {
log.log(Level.WARNING, "sip.stack.network.resolve_obtain_nw_interfaces_failed", me);
log.log(Level.WARNING, se.getMessage(), se);
}
}
if (nifs != null) {
while (nifs.hasMoreElements()) {
int addrCount = 0;
NetworkInterface nif = nifs.nextElement();
String ifName = nif.getName();
if (log.isLoggable(Level.FINE)) {
log.log(Level.FINE, me + " found interface: " + ifName);
}
for (Enumeration<InetAddress> addrs = nif.getInetAddresses();addrs.hasMoreElements();) {
InetAddress inet = addrs.nextElement();
addrCount++;
if (log.isLoggable(Level.FINE))
log.log(Level.FINE, me + " found address " + inet + " for interface " + ifName);
if (!inetAddresses.contains(inet)) {
inetAddresses.add(inet);
}
}
if (addrCount < 1) {
if (log.isLoggable(Level.FINE))
log.log(Level.FINE, me + "found no configured IP addresses for interface " + ifName);
} else {
if (log.isLoggable(Level.FINE))
log.log(Level.FINE, me + "found " + addrCount + " configured IP addresses for interface " + ifName);
}
}
}
}
private String getBestAddress(List<InetAddress> inetAddresses) {
final List<String> preferedPrefix = null;// Arrays.asList(new String[] {}); // None at the moment
/* Out of the 3 private addres classes, we should prefer
* Class A more than Class B more than Class C
*/
final List<String> avoidedClassAPrefix = Arrays.asList(new String[] { //ClassA
"10."});
final List<String> avoidedClassBPrefix = Arrays.asList(new String[] { //Class B
"172.16.", "172.17.", "172.18.", "172.19.", "172.20.", "172.21.", "172.22.", "172.23.",
"172.24.", "172.25.", "172.26.", "172.27.", "172.28.", "172.29.", "172.30.", "172.31.",
});
final List<String> avoidedClassCPrefix = Arrays.asList(new String[] { // C
"192.168."
});
String lanAddress = null;
String me = "Best address resolve";
int score = 0;
int newscore;
for (InetAddress inet : inetAddresses) {
String addrString = inet.getHostAddress();
if (startsStrWithPrefixFromList(addrString, preferedPrefix)) {
newscore = 40; // 40: preferred address
} else if (startsStrWithPrefixFromList(addrString, avoidedClassAPrefix)
|| inet.isSiteLocalAddress()) {
newscore = 20; // 20: avoid this address if possible
} else if (startsStrWithPrefixFromList(addrString, avoidedClassBPrefix)
|| inet.isSiteLocalAddress()) {
newscore = 18; // 18: avoid this address if possible
} else if (startsStrWithPrefixFromList(addrString, avoidedClassCPrefix)
|| inet.isSiteLocalAddress()) {
newscore = 15; // 15: avoid this address if possible
} else if (isLocalClient(inet)) {
newscore = 10; // 10: avoid this address if possible
} else if (inet.isLinkLocalAddress()) {
newscore = 5; // 5: avoid this address if possible
} else if (addrString.indexOf(":") >= 0) {
newscore = 25; // score 25 for IPv6 address
} else {
newscore = 30; // 30: neither preferred nor avoided
}
if (score < newscore) {
lanAddress = addrString;
score = newscore;
if (log.isLoggable(Level.FINE)) {
log.log(Level.FINE, me + "score: " + newscore + ", best so far "
+ addrString);
}
} else {
if (log.isLoggable(Level.FINE)) {
log.log(Level.FINE, me + "score: " + newscore + ", ignored " +
addrString);
}
}
}
return lanAddress;
}
private boolean isLocalClient(InetAddress inet) {
return (inet.isLoopbackAddress() || inet.isAnyLocalAddress());
}
private boolean startsStrWithPrefixFromList(String addr, List<String> prefixes) {
boolean match = false;
if (addr != null && prefixes != null) {
for (String prefix : prefixes) {
if (addr.startsWith(prefix)) {
match = true;
break;
}
}
}
return match;
}
private void addInterface(SipBindingCtx sipBindingCtx) {
TargetTuple[] tt = sipBindingCtx.getTargetTuples();
for (int i = 0; i < tt.length; i++) {
if (tt[i].getAddress() != null &&
tt[i].getAddress().isAnyLocalAddress()) {
continue;
}
SipURIImpl s = new SipURIImpl();
s.setSecure(tt[i].getProtocol().ordinal() == SipTransports.TLS);
s.setHost(tt[i].getIP());
s.setPort(tt[i].getPort());
if (!s.isSecure()) {
s.setTransportParam(tt[i].getProtocol().name());
}
if (!outboundInterfaces.contains(s)){
outboundInterfaces.add(s);
}
}
}
public static SipURIImpl [] getInterfaces(){
return outboundInterfaces.toArray(new SipURIImpl[outboundInterfaces.size()]);
}
public void setInterfaces() {
outboundInterfaces.clear();
for (String publiccontext : getPublicContexts()) {
addInterface(getPublicContext(publiccontext));
}
for (String localcontext : getLocalContexts()) {
addInterface(getLocalContext(localcontext));
}
}
public String reportBindings() {
StringBuffer buf = new StringBuffer();
for (Map.Entry<String, SipBindingCtx> entries : publiccontexts.entrySet()) {
buf.append("\ncontext: '");
buf.append(entries.getKey());
buf.append("' ");
for (TargetTuple tuple : entries.getValue().getTargetTuples()) {
buf.append(tuple);
}
}
return buf.toString();
}
class ParentCtxChangeListener implements ConfigChangeListener {
/**
* Prepares the new TargetTuples for the ctx.
* registeres CtxChangeListener
*/
public void handleConfigEvent(ConfigAddEvent event) {
updateContexts(event.getNode());
setInterfaces();
CtxChangeListener listener = new CtxChangeListener();
ctxListeners.put(event.getNode(), listener);
ConfigFactory.instance().registerConfigChangeListener(getCtxRegExp(
event.getNode()), listener);
ConfigFactory.instance().registerConfigChangeListener(getCtxSslRegExp(
event.getNode()), listener);
processNewSipBindingCtxAvalable(event.getNode());
}
public void handleConfigEvent(ConfigUpdateEvent event) {
//ignore
}
/**
* Prepares the new TargetTuples for the ctx.
* Cancels all associated leases.
* deregisteres CtxChangeListener
*/
public void handleConfigEvent(ConfigRemoveEvent event) {
SipBindingCtx sipBindingCtx = localcontexts.remove(event.getNode());
if (sipBindingCtx != null){
publiccontexts.remove(event.getNode());
//rudimentary, can be bettered by removing selectively
setInterfaces();
// should we update PUBLIC_BINDING_CTX ?
} else {
privatecontexts.remove(event.getNode());
}
CtxChangeListener listener = ctxListeners.remove(event.getNode());
if (listener != null) {
ConfigFactory.instance().deregisterConfigChangeListener(listener);
}
processSipBindingCtxRemove(event.getNode());
}
}
class CtxChangeListener implements ConfigChangeListener {
public void handleConfigEvent(ConfigAddEvent event) {
if (event.getNode().endsWith("/Ssl")) {
String ctx = getCtxFromSslNode(event.getNode());
snapshot(ctx);
processSipBindingCtxUpdated(ctx);
} else {
//ignore
}
}
public void handleConfigEvent(ConfigUpdateEvent event) {
String ctx = event.getNode();
if (event.getNode().endsWith("/Ssl")) {
ctx = getCtxFromSslNode(event.getNode());
}
snapshot(ctx);
processSipBindingCtxUpdated(ctx);
}
public void handleConfigEvent(ConfigRemoveEvent event) {
if (event.getNode().endsWith("/Ssl")) {
String ctx = getCtxFromSslNode(event.getNode());
snapshot(ctx);
processSipBindingCtxUpdated(ctx);
} else {
//ignore
}
}
private String getCtxFromSslNode(String node) {
return node.substring(0,node.length()-"/Ssl".length());
}
private void snapshot(String ctx) {
updateContexts(ctx);
setInterfaces();
}
}
class PublicCtxChangeListener implements ConfigChangeListener {
public void handleConfigEvent(ConfigAddEvent event) {
//ignore
}
/**
* Prepares the new TargetTuples for the ctx.
* Cancels all associated leases.
*/
public void handleConfigEvent(ConfigUpdateEvent event) {
currentPublicHost = null;
publiccontexts.put(PUBLIC_BINDING_CTX,
new SipBindingCtx(SipBindingResolver.INSTANCE,
PUBLIC_BINDING_CTX, resolvePublicTargetTuples(), false));
setInterfaces();
getCurrentPublicHost();
processPublicSipBindingCtxUpdated();
}
public void handleConfigEvent(ConfigRemoveEvent event) {
//ignore
}
}
}