/**
 * JaDOrT: JASMINe Deployment Orchestration Tool
 * Copyright (C) 2008-2009 Bull S.A.S.
 * Copyright (C) 2008-2009 France Telecom R&D
 * Contact: jasmine@ow2.org
 *
 * This library 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 any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id: JkUpdateAccessor.java 2965 2009-01-12 12:14:51Z alitokmen $
 * --------------------------------------------------------------------------
 */
package org.ow2.jasmine.jadort.service.action.modJK;

import java.net.HttpURLConnection;

import org.apache.jk.status.JkBalancer;
import org.apache.jk.status.JkBalancerMember;
import org.apache.jk.status.JkStatus;
import org.apache.jk.status.JkStatusAccessor;
import org.apache.tomcat.util.digester.Digester;

/**
 * Creates the HTTP GET requests for mod_jk updates.
 * 
 * @author Malek Chahine
 * @author Remy Bresson
 * @author S. Ali Tokmen
 */
public class JkUpdateAccessor extends JkStatusAccessor {

    /**
     * Parses Apache mod_jk Status from base url http://host:port/jkstatus
     * 
     * @param url mod_jk manager URL.
     * @param username User name to use when connecting, null not to use any.
     * @param password Password to use when connecting, null not to use any.
     * @param balancer Balancer to update.
     * @return Current status.
     * @throws JkConnectionException If response parsing fails.
     */
    public JkStatus update(final String url, final String username, final String password, final JkBalancer balancer)
        throws JkConnectionException {
        if (url == null || "".equals(url)) {
            return null;
        }
        HttpURLConnection hconn = null;
        JkStatus status = null;

        try {
            hconn = this.openConnection(url + "?mime=xml&cmd=update" + this.createUpdateParameterLink(balancer), username,
                password);
            Digester digester = JkActionParser.getActionDigester();
            synchronized (digester) {
                status = (JkStatus) digester.parse(hconn.getInputStream());
            }
        } catch (Exception e) {
            throw new JkConnectionException("Failed parsing response", e);
        } finally {
            if (hconn != null) {
                try {
                    hconn.disconnect();
                } catch (Throwable u) {
                    ;
                }
                hconn = null;
            }
        }
        return status;
    }

    /**
     * Create JkStatus worker update link
     * <ul>
     * </b>http://host:port/jkstatus?cmd=update&mime=txt&w=loadbalancer&lm=1&ll=
     * 1&lr=2&lt=60&ls=true&lf=false <br/>
     * <br/>
     * Tcp worker parameter: <br/>
     * <ul>
     * <li><b>w:<b/> name loadbalancer</li>
     * <li><b>lm:<b/> method (lb strategy)</li>
     * <li><b>ll:<b/> lock</li>
     * <li><b>lr:<b/> retries</li>
     * <li><b>lt:<b/> recover wait timeout</li>
     * <li><b>ls:<b/> sticky session</li>
     * <li><b>lf:<b/> force sticky session</li>
     * </ul>
     * <ul>
     * <li>lm=1 or Requests</li>
     * <li>lm=2 or Traffic</li>
     * <li>lm=3 or Busyness</li>
     * <li>lm=4 or Sessions</li>
     * </ul>
     * <ul>
     * <li>ll=1 or Optimistic</li>
     * <li>ll=2 or Pessimistic</li>
     * </ul>
     * 
     * @return create jkstatus update worker link
     */
    protected String createUpdateParameterLink(final JkBalancer balancer) {
        StringBuffer sb = new StringBuffer();
        String lbMethod = balancer.getMethod();
        String locking = balancer.getLock();

        sb.append("&w=");
        sb.append(balancer.getName());
        sb.append("&ls=");
        sb.append(balancer.isSticky_session());
        sb.append("&lf=");
        sb.append(balancer.isSticky_session_force());
        sb.append("&lr=");
        sb.append(balancer.getRetries());
        sb.append("&lt=");
        sb.append(balancer.getRecover_time());

        if ("Request".equals(lbMethod)) {
            sb.append("&lm=0");
        } else if ("Traffic".equals(lbMethod)) {
            sb.append("&lm=1");
        } else if ("Busyness".equals(lbMethod)) {
            sb.append("&lm=2");
        } else if ("Sessions".equals(lbMethod)) {
            sb.append("&lm=3");
        }
        if ("Optimistic".equals(locking)) {
            sb.append("&ll=0");
        } else if ("Pessimistic".equals(locking)) {
            sb.append("&ll=1");
        }
        return sb.toString();
    }

    /**
     * Parses Apache mod_jk Status from base url http://host:port/jkstatus
     * 
     * @param url mod_jk manager URL.
     * @param username User name to use when connecting, null not to use any.
     * @param password Password to use when connecting, null not to use any.
     * @param balancer Balancer to update.
     * @param balancerMember Balancer member to update.
     * @return Current status.
     * @throws JkConnectionException If response parsing fails.
     */
    public JkStatus update(final String url, final String username, final String password, final JkBalancer balancer,
        final JkBalancerMember balancerMember) throws JkConnectionException {
        if (url == null || "".equals(url)) {
            return null;
        }
        HttpURLConnection hconn = null;
        JkStatus status = null;

        try {
            hconn = this.openConnection(
                url + "?mime=xml&cmd=update" + this.createUpdateParameterLink(balancer, balancerMember), username, password);
            Digester digester = JkActionParser.getActionDigester();
            synchronized (digester) {
                status = (JkStatus) digester.parse(hconn.getInputStream());
            }
        } catch (Exception e) {
            throw new JkConnectionException("Failed parsing response", e);
        } finally {
            if (hconn != null) {
                try {
                    hconn.disconnect();
                } catch (Throwable u) {
                    ;
                }
                hconn = null;
            }
        }
        return status;
    }

    /**
     * Create JkStatus worker update link
     * <ul>
     * </b>http://host:port/jkstatus?cmd=update&mime=txt&w=loadbalancer&sw=
     * member&wa= 0&wf=1&wn=memberName&wr=&wc=&wd=0 <br/>
     * <br/>
     * Tcp worker parameter: <br/>
     * <ul>
     * <li><b>w:<b/> name loadbalancer</li>
     * <li><b>sw:<b/> name member</li>
     * <li><b>wa:<b/> activation</li>
     * <li><b>wf:<b/> LB factor</li>
     * <li><b>wn:<b/> route</li>
     * <li><b>wr:<b/> redirect route</li>
     * <li><b>wc:<b/> cluster domain</li>
     * <li><b>wd:<b/> distance</li>
     * </ul>
     * <ul>
     * <li>wa=1 or Active or ACT</li>
     * <li>wa=2 or Disabled or DIS</li>
     * <li>wa=3 or Stopped or STP</li>
     * </ul>
     * 
     * @return create jkstatus update worker link
     */
    protected String createUpdateParameterLink(final JkBalancer balancer, final JkBalancerMember balancerMember) {
        StringBuffer sb = new StringBuffer();
        String activation = balancerMember.getActivation();

        sb.append("&w=");
        sb.append(balancer.getName());
        sb.append("&sw=");
        sb.append(balancerMember.getName());
        if ("ACT".equals(activation)) {
            sb.append("&wa=0");
        } else if ("DIS".equals(activation)) {
            sb.append("&wa=1");
        } else if ("STP".equals(activation)) {
            sb.append("&wa=2");
        }
        sb.append("&wf=");
        sb.append(balancerMember.getLbfactor());
        sb.append("&wn=");
        sb.append(balancerMember.getRoute());
        sb.append("&wr=");
        sb.append(balancerMember.getRedirect());
        sb.append("&wc=");
        sb.append(balancerMember.getDomain());
        sb.append("&wd=");
        sb.append(balancerMember.getDistance());
        return sb.toString();
    }
}
