/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.stratos.load.balancer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.stratos.load.balancer.algorithm.AlgorithmContext;
import org.apache.stratos.load.balancer.algorithm.LoadBalanceAlgorithm;
import org.apache.stratos.load.balancer.conf.LoadBalancerConfiguration;
import org.apache.stratos.load.balancer.context.LoadBalancerContext;
import org.apache.stratos.messaging.domain.topology.Cluster;
import org.apache.stratos.messaging.domain.topology.Member;

import java.util.ArrayList;

/**
 * Implements core load balancing logic for identifying the next member
 * according to the incoming request information.
 */
public class RequestDelegator {
    private static final Log log = LogFactory.getLog(RequestDelegator.class);

    private LoadBalanceAlgorithm algorithm;

    public RequestDelegator(LoadBalanceAlgorithm algorithm) {
        this.algorithm = algorithm;
    }

    public Member findNextMemberFromHostName(String hostName, String messageId) {
        if (hostName == null)
            return null;

        long startTime = System.currentTimeMillis();

        Cluster cluster = LoadBalancerContext.getInstance().getHostNameClusterMap().getCluster(hostName);
        if (cluster != null) {
        	if (log.isDebugEnabled()) {
        		log.debug(String.format("Cluster %s identified for request %s", cluster.getClusterId(), messageId));
        	}
            Member member = findNextMemberInCluster(cluster);
            if (member != null) {
                if (log.isDebugEnabled()) {
                    long endTime = System.currentTimeMillis();
                    log.debug(String.format("Next member identified in %dms: [service] %s [cluster] %s [member] %s [request-id] %s", 
                    		(endTime - startTime), member.getServiceName(), member.getClusterId(), member.getMemberId(), messageId));
                }
            }
            return member;
        }
        return null;
    }

    public Member findNextMemberFromTenantId(String hostName, int tenantId) {
        long startTime = System.currentTimeMillis();

        // Find cluster from host name and tenant id
        Cluster cluster = LoadBalancerContext.getInstance().getMultiTenantClusterMap().getCluster(hostName, tenantId);
        if (cluster != null) {
            Member member = findNextMemberInCluster(cluster);
            if (member != null) {
                if (log.isDebugEnabled()) {
                    long endTime = System.currentTimeMillis();
                    log.debug(String.format("Next member identified in %dms: [service] %s [cluster] %s [tenant-id] %d [member] %s",
                            (endTime - startTime), member.getServiceName(), member.getClusterId(), tenantId, member.getMemberId()));
                }
            }
            return member;
        }
        return null;
    }

    /**
     * This operation should be synchronized in order to find a member correctly.
     */
    private synchronized Member findNextMemberInCluster(Cluster cluster) {
        // Find algorithm context of the cluster
        ClusterContext clusterContext = LoadBalancerContext.getInstance().getClusterIdClusterContextMap().getClusterContext(cluster.getClusterId());
        if (clusterContext == null) {
            clusterContext = new ClusterContext(cluster.getServiceName(), cluster.getClusterId());
            LoadBalancerContext.getInstance().getClusterIdClusterContextMap().addClusterContext(clusterContext);
        }

        AlgorithmContext algorithmContext = clusterContext.getAlgorithmContext();
        if (algorithmContext == null) {
            algorithmContext = new AlgorithmContext(cluster.getServiceName(), cluster.getClusterId());
            clusterContext.setAlgorithmContext(algorithmContext);
        }
        
		algorithm.setMembers(new ArrayList<Member>(cluster.getMembers()));
		Member member = algorithm.getNextMember(algorithmContext);
		
        if (member == null) {
            if (log.isWarnEnabled()) {
                log.warn(String.format("Could not find a member in cluster: [service] %s [cluster] %s", cluster.getServiceName(), cluster.getClusterId()));
            }
        }
        return member;
    }

    public boolean isTargetHostValid(String hostName) {
        if (hostName == null)
            return false;

        boolean valid = LoadBalancerContext.getInstance().getHostNameClusterMap().containsCluster(hostName);
        if ((!valid) && (LoadBalancerConfiguration.getInstance().isMultiTenancyEnabled())) {
            valid = LoadBalancerContext.getInstance().getMultiTenantClusterMap().containsClusters(hostName);
        }
        return valid;
    }
}

@@ -2090,17 +2090,20 @@
         
-%09
+    
 if (log.
@@ -2130,18 +2130,24 @@
         
-%09%09
+        
 log.debu
@@ -2247,17 +2247,20 @@
         
-%09
+    
 %7D%0A      
@@ -2588,17 +2588,16 @@
 id%5D %25s%22,
- 
 %0A       
@@ -2609,18 +2609,24 @@
         
-%09%09
+        
 (endTime
@@ -2784,32 +2784,204 @@
 mber;%0A        %7D%0A
+        else %7B%0A            if(log.isWarnEnabled()) %7B%0A                log.warn(String.format(%22Could not find a cluster for hostname %25s%22, hostName));%0A            %7D%0A        %7D%0A
         return n

Add proper logs