package com.ericsson.ssa.sip.dns;
import com.ericsson.ssa.config.ConfigFactory;
import com.ericsson.ssa.config.SimpleConfig;
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.dns.Translator.MappingTuple;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.ElementProperty;
import com.sun.enterprise.config.serverbeans.ServerBeansFactory;
import com.sun.enterprise.server.ApplicationServer;
import com.sun.enterprise.server.ServerContext;
import org.jvnet.glassfish.comms.util.LogUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class handles reading the configuration for the URI-canonicalization and Number Normalization.
* It also listens for changes to changes in the configuration. The class then applies the configuration to the {@link Translator}.
* <p>
* A mapping for a URI-alias is specified as follows:<br>
* < property name="uri-alias-mapping < seq-number >" value=" < plugin-class-name > ; < regular-expression-pattern > " /><br>
* seq-number: defines the order in which the patterns are tested<br>
* plugin-class-name: this is the fully qualified of the plugin-class<br>
* regular-expression-pattern: the regular expression that is applied on the URI and which selects the plugin-class if it is matched.<br>
* Example:<br>
* < property name="uri-alias-mapping1" value="com.myapp.MyUriCanonicalizer ; *." / >
* <p>
* A mapping for a phone-context is specified as follows:<br>
* < property name="phone-context-mapping < seq-number >" value=" < plugin-class-name > ; < regular-expression-pattern > " /><br>
* seq-number: defines the order in which the patterns are tested<br>
* plugin-class-name: this is the fully qualified of the plugin-class<br>
* regular-expression-pattern: the regular expression that is applied on the phone-context and which selects the plugin-class if it is matched.<br>
* Example:<br>
* < property name="phone-context-mapping1" value="com.myapp.MyNumberNormalizer ; *." / >
* <p>
*
*/
public class ConfigurationHandler {
private static final String PHONE_CONTEXT_MAPPING = "phone-context-mapping";
private static final String URI_ALIAS_MAPPING = "uri-alias-mapping";
private static final String CFG_SIP_SERVICE = "/SipService";
private static final String CFG_SIP_SERVICE_ELEMENT_PROPERTY = CFG_SIP_SERVICE +
"/ElementProperty";
private static final Logger logger = LogUtil.SIP_LOGGER.getLogger();
private SipServiceConfigListener listener;
private Translator translator;
/**
* Create it!
*/
public ConfigurationHandler(Translator translator) {
this.translator = translator;
init();
}
/**
* Cleanup; deregister config listener.
*/
public void cleanup() {
ConfigFactory.instance().deregisterConfigChangeListener(listener);
}
private void init() {
try {
// Read the property elements below the sip-service
ServerContext sc = ApplicationServer.getServerContext();
Config cfg = ServerBeansFactory.getConfigBean(sc.getConfigContext());
List<Translator.MappingTuple> uriAliasMappings = new ArrayList<MappingTuple>();
List<Translator.MappingTuple> phoneContextMappings = new ArrayList<MappingTuple>();
for (ElementProperty elementProperty : cfg.getSipService()
.getElementProperty()) {
analyzeProperty(elementProperty.getName(), elementProperty.getValue(), uriAliasMappings, phoneContextMappings);
}
translator.loadUriAliasHandlers(uriAliasMappings);
translator.loadPhoneContextHandlers(phoneContextMappings);
// Add listener to configuration changes in the sip-listener element
listener = new SipServiceConfigListener();
ConfigFactory.instance()
.registerConfigChangeListener(CFG_SIP_SERVICE, listener);
} catch (ConfigException e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING,
"Failed to load configuration of phone-context handlers and URI-alias handlers: " +
e);
}
}
}
/**
* Analyzes the property and possibly loads the plugin specified (in case it specifies a
* uri-alias or phone-context mapping)
* @param name the property name
* @param value the property value
*/
private void analyzeProperty(String name, String value, List<MappingTuple> uriAliasMappings, List<MappingTuple> phoneContextMappings) {
boolean isUriAlias = false;
// Check if it a mapping
if (name.startsWith(URI_ALIAS_MAPPING)) {
isUriAlias = true;
} else if (name.startsWith(PHONE_CONTEXT_MAPPING)) {
isUriAlias = false;
} else {
return;
}
StringTokenizer st = new StringTokenizer(value, ";");
String handlerClassName = null;
String pattern = null;
if (st.hasMoreTokens()) {
handlerClassName = st.nextToken().trim();
}
if (st.hasMoreTokens()) {
pattern = st.nextToken().trim();
}
if ((name == null) || (pattern == null)) {
// This was not a valid mapping
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING,
"The mapping name=\"" + name + "\" value=\"" + value +
"\" was not specified correctly");
}
return;
}
if (isUriAlias) {
uriAliasMappings.add(new Translator.MappingTuple(name, handlerClassName, pattern));
} else {
phoneContextMappings.add(new Translator.MappingTuple(name, handlerClassName, pattern));
}
}
private final class SipServiceConfigListener implements ConfigChangeListener {
public void handleConfigEvent(ConfigAddEvent event) {
SimpleConfig cfg = (SimpleConfig) event.getSource();
Map<String, String> properties = cfg.getAll(CFG_SIP_SERVICE_ELEMENT_PROPERTY);
setupTranslator(properties);
}
public void handleConfigEvent(ConfigUpdateEvent event) {
SimpleConfig cfg = (SimpleConfig) event.getSource();
Map<String, String> properties = cfg.getAll(CFG_SIP_SERVICE_ELEMENT_PROPERTY);
setupTranslator(properties);
}
public void handleConfigEvent(ConfigRemoveEvent event) {
SimpleConfig cfg = (SimpleConfig) event.getSource();
Map<String, String> properties = cfg.getAll(CFG_SIP_SERVICE_ELEMENT_PROPERTY);
setupTranslator(properties);
}
private void setupTranslator(Map<String, String> properties) {
List<Translator.MappingTuple> uriAliasMappings = new ArrayList<MappingTuple>();
List<Translator.MappingTuple> phoneContextMappings = new ArrayList<MappingTuple>();
for (Map.Entry<String, String> entry : properties.entrySet()) {
analyzeProperty(entry.getKey(), entry.getValue(), uriAliasMappings, phoneContextMappings);
}
translator.loadUriAliasHandlers(uriAliasMappings);
translator.loadPhoneContextHandlers(phoneContextMappings);
}
}
}