/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.mobicents.tools.sip.balancer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import javax.sip.message.Request;
import javax.sip.message.Response;
import org.apache.log4j.Logger;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.http.Cookie;
import org.jboss.netty.handler.codec.http.CookieDecoder;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.mobicents.tools.configuration.LoadBalancerConfiguration;
import org.mobicents.tools.heartbeat.api.Node;
public abstract class DefaultBalancerAlgorithm implements BalancerAlgorithm {
private static final Logger logger = Logger.getLogger(DefaultBalancerAlgorithm.class.getCanonicalName());
protected Properties properties;
protected BalancerContext balancerContext;
protected InvocationContext invocationContext;
protected Iterator<Entry<KeySip, Node>> ipv4It = null;
protected Iterator<Entry<KeySip, Node>> ipv6It = null;
protected Iterator<Node> httpRequestIterator = null;
protected Iterator <Node> instanceIdIterator = null;
protected LoadBalancerConfiguration lbConfig;
// public void setProperties(Properties properties) {
// this.properties = properties;
// }
public LoadBalancerConfiguration getConfiguration() {
return lbConfig;
}
public void setConfiguration(LoadBalancerConfiguration lbConfig) {
this.lbConfig = lbConfig;
}
public void setInvocationContext(InvocationContext ctx) {
this.invocationContext = ctx;
}
public InvocationContext getInvocationContext() {
return invocationContext;
}
public BalancerContext getBalancerContext() {
return balancerContext;
}
// public Properties getProperties() {
// return properties;
// }
public void processInternalRequest(Request request) {
}
public void configurationChanged() {
}
public synchronized Node processHttpRequest(HttpRequest request) {
if(invocationContext.sipNodeMap(false).size()>0) {
String instanceId = getInstanceId(request);
if(instanceId!=null)
return getNodeByInstanceId(instanceId);
String httpSessionId = null;
httpSessionId = getUrlParameters(request.getUri()).get("jsessionid");
if(httpSessionId == null)
httpSessionId = getParameterFromCookie(request, "jsessionid");
if(httpSessionId != null) {
int indexOfDot = httpSessionId.lastIndexOf('.');
if(indexOfDot>0 && indexOfDot<httpSessionId.length()) {
String jvmRoute = httpSessionId.substring(indexOfDot + 1);
Node node = balancerContext.jvmRouteToSipNode.get(jvmRoute);
if(node != null) {
if(invocationContext.sipNodeMap(false).containsValue(node)) {
return node;
}
}
}
logger.warn("As a failsafe if there is no jvmRoute. LB will send request to node accordingly RR algorithm");
if(httpRequestIterator==null)
httpRequestIterator = invocationContext.sipNodeMap(false).values().iterator();
if(httpRequestIterator.hasNext())
{
return httpRequestIterator.next();
}
else
{
httpRequestIterator = invocationContext.sipNodeMap(false).values().iterator();
if(httpRequestIterator.hasNext())
{
return httpRequestIterator.next();
}
else
return null;
}
}
//if request doesn't have jsessionid (very first request), we choose next node using round robin algorithm
if(httpRequestIterator==null)
httpRequestIterator = invocationContext.sipNodeMap(false).values().iterator();
if(httpRequestIterator.hasNext())
return httpRequestIterator.next();
else
{
httpRequestIterator = invocationContext.sipNodeMap(false).values().iterator();
if(httpRequestIterator.hasNext())
return httpRequestIterator.next();
else
return null;
}
} else {
String unavailaleHost = getConfiguration().getHttpConfiguration().getUnavailableHost();
if(unavailaleHost != null) {
Node node = new Node(unavailaleHost, unavailaleHost);
node.getProperties().put("httpPort", "" + 80);
return node;
} else {
return null;
}
}
}
@Override
public void proxyMessage(ChannelHandlerContext ctx, MessageEvent e){}
@Override
public boolean blockInternalRequest(Request request){
return false;
}
public Node processAssignedExternalRequest(Request request, Node assignedNode) {
return assignedNode;
}
private HashMap<String,String> getUrlParameters(String url) {
HashMap<String,String> parameters = new HashMap<String, String>();
int start = url.lastIndexOf('?');
if(start>0 && url.length() > start +1) {
url = url.substring(start + 1);
} else {
return parameters;
}
String[] tokens = url.split("&");
for(String token : tokens) {
String[] params = token.split("=");
if(params.length<2) {
parameters.put(token, "");
} else {
parameters.put(params[0], params[1]);
}
}
return parameters;
}
private String getInstanceId(HttpRequest request)
{
String url = request.getUri();
String[] tokens = url.split("/");
if(tokens.length>6&&tokens[3].equals("Accounts")&&tokens[5].startsWith("Calls"))
{
if(tokens[6].split("-").length>1)
{
String instanceId = tokens[6].split("-")[0];
url = url.replace(instanceId+"-", "");
request.setUri(url);
return instanceId;
}
// else
// {
// url = url.replace("/"+tokens[6], "");
// request.setUri(url);
// return tokens[6];
// }
}
return null;
}
private String getParameterFromCookie(HttpRequest request, String parameter){
CookieDecoder cookieDocoder = new CookieDecoder();
String cookieString = request.getHeader("Cookie");
if(cookieString != null) {
Set<Cookie> cookies = cookieDocoder.decode(cookieString);
Iterator<Cookie> cookieIterator = cookies.iterator();
while(cookieIterator.hasNext()) {
Cookie c = cookieIterator.next();
if(c.getName().equalsIgnoreCase("jsessionid")) {
return c.getValue();
}
}
}
return null;
}
public void processInternalResponse(Response response,Boolean isIpV6) {
}
public void processExternalResponse(Response response,Boolean isIpV6) {
}
public void start() {
}
public void stop() {
}
public void nodeAdded(Node node) {
}
public void nodeRemoved(Node node) {
}
public void jvmRouteSwitchover(String fromJvmRoute, String toJvmRoute) {
}
public void assignToNode(String id, Node node) {
}
private Node getNodeByInstanceId(String instanceId)
{
if(logger.isDebugEnabled())
logger.debug("Node by instanceId("+instanceId+") getting");
Node node = invocationContext.httpNodeMap.get(new KeyHttp(instanceId));
if(node!=null)
{
return node;
}
else
{
if(instanceIdIterator==null)
instanceIdIterator = invocationContext.httpNodeMap.values().iterator();
logger.warn("instanceId exists in HTTP request but doesn't match to any node. LB will send request to node accordingly RR algorithm");
if(instanceIdIterator.hasNext())
return instanceIdIterator.next();
else
{
instanceIdIterator = invocationContext.httpNodeMap.values().iterator();
if(instanceIdIterator.hasNext())
return instanceIdIterator.next();
else
return null;
}
}
}
}