/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. 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 org.jvnet.glassfish.comms.admin.gui.extensions.handlers;

import com.sun.enterprise.tools.admingui.handlers.ConfigurationHandlers;
import com.sun.enterprise.tools.admingui.util.GuiUtil;
import com.sun.enterprise.tools.admingui.util.JMXUtil;

import com.sun.jsftemplating.annotation.Handler;
import com.sun.jsftemplating.annotation.HandlerInput;
import com.sun.jsftemplating.annotation.HandlerOutput;
import com.sun.jsftemplating.layout.descriptors.handler.HandlerContext;

import org.jvnet.glassfish.comms.admin.gui.extensions.util.SipUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

import javax.faces.model.SelectItem;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.ObjectName;

import javax.net.ssl.SSLServerSocketFactory;


/**
 *  These are the handlers for sip-service element and its sub-elements
 *  @author irfan
 */
public class SipServiceHandlers {
    /*  sip-listener attribute names */
    public static final String[] listenerAttributeNames = new String[] {
            "id", "port", "address", "transport", "enabled"
        };

    /*  sip-listener.ssl attribute names */
    public static final String[] sslAttributeNames = new String[] {
            "cert-nickname", "ssl2-enabled", "ssl2-ciphers", "ssl3-enabled",
            "ssl3-tls-ciphers", "tls-enabled", "tls-rollback-enabled",
            "client-auth-enabled"
        };
    public static List sipServiceSkipList = new ArrayList();
    protected static String[] COMMON_CIPHERS = {
            "SSL_RSA_WITH_RC4_128_MD5", "SSL_RSA_WITH_RC4_128_SHA",
            "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA",
            "SSL_RSA_WITH_3DES_EDE_CBC_SHA"
        };
    protected static String[] BIT_CIPHERS = {
            "SSL_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA",
            "SSL_DHE_DSS_WITH_DES_CBC_SHA", "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
            "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
        };

    static {
        sipServiceSkipList.add("accessLoggingEnabled");
        sipServiceSkipList.add("accessLogWriteInterval");
        sipServiceSkipList.add("accessLogBufferSize");
    }

    /**
     *  <p> This handler saves the sip-service properties.</p>
     *  <p> Input value:  "ConfigName"         -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "ObjectName"         -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "newProps"         -- Type: <code>java.util.Map</code></p>
     *  <p> Input value:  "accessLoggingEnabled"         -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "accessLogWriteInterval"         -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "accessLogBufferSize"         -- Type: <code>java.lang.String</code></p>
     */
    @Handler(id = "saveSipService", input =  {
        @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "newProps", type = Map.class)
        , @HandlerInput(name = "accessLoggingEnabled", type = String.class)
        , @HandlerInput(name = "accessLogWriteInterval", type = String.class)
        , @HandlerInput(name = "accessLogBufferSize", type = String.class)
    }
    )
    public static void saveSipService(HandlerContext handlerContext) {
        String configName = (String) handlerContext.getInputValue("ConfigName");
        String objectName = (String) handlerContext.getInputValue("ObjectName");
        ObjectName sipService = (ObjectName) JMXUtil.invoke(objectName,
                "getSipService", new Object[] { "" },
                new String[] { "java.lang.String" });

        HashMap props = (HashMap) handlerContext.getInputValue("newProps");

        SipUtil.updateProperties(sipService, props, sipServiceSkipList);

        // Change the props that are always shown on the page.
        SipUtil.changeProperty(sipService, "accessLoggingEnabled",
            (String) handlerContext.getInputValue("accessLoggingEnabled"));
        SipUtil.changeProperty(sipService, "accessLogWriteInterval",
            (String) handlerContext.getInputValue("accessLogWriteInterval"));
        SipUtil.changeProperty(sipService, "accessLogBufferSize",
            (String) handlerContext.getInputValue("accessLogBufferSize"));
    }

    /**
     *  <p> This handler gets the sip-service properties.</p>
     *  <p> Input value: "ObjectName"    --Type: <code>java.lang.String</code> </p>
     *  <p> Input value: "ConfigName"    --Type: <code>java.lang.String</code> </p>
     *  <p> Output value: "accessLogBufferSize"    --Type: <code>java.lang.String</code> </p>
     *  <p> Output value: "accessLogWriteInterval"    --Type: <code>java.lang.String</code> </p>
     *  <p> Output value: "accessLoggingEnabled"    --Type: <code>java.lang.Boolean</code> </p>
     *  <p> Output value: "Properties"    --Type: <code>java.util.Map</code> </p>)
     */
    @Handler(id = "getSipService", input =  {
        @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
    }
    , output =  {
        @HandlerOutput(name = "accessLogBufferSize", type = String.class)
        , @HandlerOutput(name = "accessLogWriteInterval", type = String.class)
        , @HandlerOutput(name = "accessLoggingEnabled", type = Boolean.class)
        , @HandlerOutput(name = "Properties", type = Map.class)
    }
    )
    public static void getSipService(HandlerContext handlerContext) {
        String objectName = (String) handlerContext.getInputValue("ObjectName");
        String configName = (String) handlerContext.getInputValue("ConfigName");
        ObjectName sipService = (ObjectName) JMXUtil.invoke(objectName,
                "getSipService", new Object[] { "" },
                new String[] { "java.lang.String" });
        Map props = SipUtil.getProperties(sipService);

        try {
            handlerContext.setOutputValue("accessLogBufferSize",
                props.remove("accessLogBufferSize"));
            handlerContext.setOutputValue("accessLogWriteInterval",
                props.remove("accessLogWriteInterval"));

            String alog = (String) props.remove("accessLoggingEnabled");
            Boolean accessLoggingEnabled = true;

            if (GuiUtil.isEmpty(alog)) {
                accessLoggingEnabled = true;
            } else {
                accessLoggingEnabled = (alog.equals("true")) ? true : false;
            }

            handlerContext.setOutputValue("accessLoggingEnabled",
                accessLoggingEnabled);
            handlerContext.setOutputValue("Properties", props);
        } catch (Exception ex) {
            GuiUtil.handleException(handlerContext, ex);
        }
    }

    /**
     *  <p> This handler gets the sip listeners within a sip service.</p>
     *  <p> Input value:  "ObjectName"  -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "ConfigName"  -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "selectedRows"  -- Type: <code>java.util.List</code></p>
     *  <p> Output value: "Result"    -- Type: <code>java.util.List</code></p>
     */
    @Handler(id = "getSipListenersList", input =  {
        @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "selectedRows", type = List.class)
    }
    , output =  {
        @HandlerOutput(name = "Result", type = List.class)
    }
    )
    public static void getSipListenersList(HandlerContext handlerContext) {
        List result = new ArrayList();

        try {
            ObjectName configBeanName = new ObjectName((String) handlerContext.getInputValue(
                        "ObjectName"));
            ObjectName[] retValue = (ObjectName[]) JMXUtil.invoke(configBeanName,
                    "listSipListeners", new Object[] { "" },
                    new String[] { "java.lang.String" });

            for (ObjectName object : retValue) {
                String id = object.getKeyProperty("id");
                ObjectName sipListener = SipUtil.getSipListener(configBeanName,
                        id);
                HashMap row = SipUtil.getAttributeValues(sipListener,
                        listenerAttributeNames);
                row.put("selected", false);
                result.add(row);
            }
        } catch (Exception ex) {
            GuiUtil.handleException(handlerContext, ex);
        }

        handlerContext.setOutputValue("Result", result);
    }

    /**
     *  <p> The handler gets the various transport protocols available</p>
     *  <p> Input value:  "ConfigName" -- Type: <code>java.lang.String</code></p>
     *  <p> Output value: "Protocols"  -- Type: <code>java.lang.String</code></p>
     */
    @Handler(id = "getSipListenerTransportProtocols", input =  {
        @HandlerInput(name = "ConfigName", type = String.class, required = true)
    }
    , output =  {
        @HandlerOutput(name = "Protocols", type = SelectItem[].class)
    }
    )
    public static void getSipListenerTransportProtocols(
        HandlerContext handlerContext) {
        String configName = (String) handlerContext.getInputValue("ConfigName");
        String[] labels = { "UDP and TCP", "TLS" };
        String[] values = { "udp_tcp", "tls" };
        SelectItem[] options = ConfigurationHandlers.getOptions(values, labels);
        handlerContext.setOutputValue("Protocols", options);
    }

    /**
     *  <p> This handler is used to get the sip listener attributes and properties. </p>
     *  <p> Input value:  "Edit"  -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "FromStep2"  -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "ConfigName"  -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "SipName"  -- Type: <code>java.lang.String</code></p>
     *  <p> Input value:  "ObjectName"  -- Type: <code>java.lang.String</code></p>
     *
     *  <p> Output value: "Listener"  -- Type: <code>java.lang.String</code></p>
     *  <p> Output value: "Address"  -- Type: <code>java.lang.String</code></p>
     *  <p> Output value: "Port"  -- Type: <code>java.lang.String</code></p>
     *  <p> Output value: "Transport"  -- Type: <code>java.lang.String</code></p>
     *  <p> Output value: "Properties"  -- Type: <code>java.lang.String</code></p>
     */
    @Handler(id = "getSipListenerValues", input =  {
        @HandlerInput(name = "Edit", type = Boolean.class, required = true)
        , @HandlerInput(name = "FromStep2", type = Boolean.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "SipName", type = String.class, required = true)
        , @HandlerInput(name = "ObjectName", type = String.class, required = true)
    }
    , output =  {
        @HandlerOutput(name = "Listener", type = Boolean.class)
        , @HandlerOutput(name = "Address", type = String.class)
        , @HandlerOutput(name = "Port", type = String.class)
        , @HandlerOutput(name = "Transport", type = String.class)
        , @HandlerOutput(name = "Properties", type = Map.class)
    }
    )
    public static void getSipListenerValues(HandlerContext handlerContext) {
        try {
            Boolean edit = (Boolean) handlerContext.getInputValue("Edit");
            Boolean fromStep2 = (Boolean) handlerContext.getInputValue(
                    "FromStep2");

            if (!edit) {
                if ((fromStep2 == null) || (!fromStep2)) {
                    handlerContext.getFacesContext().getExternalContext()
                                  .getSessionMap().put("sipProps", new HashMap());
                    handlerContext.getFacesContext().getExternalContext()
                                  .getSessionMap().put("sslProps", null);
                    //TODO need a better way to get the default values
                    handlerContext.setOutputValue("Listener", true);
                    handlerContext.setOutputValue("Transport", "udp_tcp");
                } else {
                    Map props = (Map) handlerContext.getFacesContext()
                                                    .getExternalContext()
                                                    .getSessionMap()
                                                    .get("sipProps");
                    handlerContext.setOutputValue("Listener",
                        props.get("enabled"));
                    handlerContext.setOutputValue("Address",
                        props.get("address"));
                    handlerContext.setOutputValue("Port", props.get("port"));
                    handlerContext.setOutputValue("Transport",
                        props.get("transport"));
                    handlerContext.setOutputValue("Properties",
                        props.get("options"));
                }

                return;
            }

            // Edit page
            String listenerName = (String) handlerContext.getInputValue(
                    "SipName");
            ObjectName sipConfig = new ObjectName((String) handlerContext.getInputValue(
                        "ObjectName"));
            ObjectName sipListener = SipUtil.getSipListener(sipConfig,
                    listenerName);
            HashMap listenerProps = SipUtil.getAttributeValues(sipListener,
                    listenerAttributeNames);

            handlerContext.setOutputValue("Listener",
                listenerProps.get("enabled"));
            handlerContext.setOutputValue("Address",
                listenerProps.get("address"));
            handlerContext.setOutputValue("Port", listenerProps.get("port"));
            handlerContext.setOutputValue("Transport",
                listenerProps.get("transport"));

            Map<String, String> pMap = SipUtil.getProperties(sipListener);

            handlerContext.setOutputValue("Properties", pMap);
        } catch (Exception ex) {
            GuiUtil.handleException(handlerContext, ex);
        }
    }

    /**
     *  <p> This handler saves the sip listener attribute values and properties. The function is called
     *  from both the edit sip listener as well as the new sip listener tabs. In case of new the code
     *  updates the session sipProps map with the values which have been furnished by the user.</p>
     *
     *  <p> Input value: "ObjectName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "ConfigName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "SipName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Edit"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "Address"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Port"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Listener"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "Transport"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "AddProps"   --Type: <code>java.util.Map</code>
     *  <p> Input value: "RemoveProps"   --Type: <code>java.util.ArrayList</code>
     */
    @Handler(id = "saveSipListenerValues", input =  {
        @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "SipName", type = String.class, required = true)
        , @HandlerInput(name = "Edit", type = Boolean.class, required = true)
        , @HandlerInput(name = "Address", type = String.class, required = true)
        , @HandlerInput(name = "Port", type = String.class, required = true)
        , @HandlerInput(name = "Listener", type = Boolean.class)
        , @HandlerInput(name = "Transport", type = String.class)
        , @HandlerInput(name = "AddProps", type = Map.class)
        , @HandlerInput(name = "RemoveProps", type = ArrayList.class)
    }
    )
    public static void saveSipListenerValues(HandlerContext handlerContext) {
        String configName = (String) handlerContext.getInputValue("ConfigName");
        String objectName = (String) handlerContext.getInputValue("ObjectName");
        String listenerName = (String) handlerContext.getInputValue("SipName");
        String address = (String) handlerContext.getInputValue("Address");
        String transport = (String) handlerContext.getInputValue("Transport");
        String port = (String) handlerContext.getInputValue("Port");
        Boolean enabled = (Boolean) handlerContext.getInputValue("Listener");

        Boolean edit = (Boolean) handlerContext.getInputValue("Edit");

        if (!edit) {
            // Creating a new sip listener
            Map sipPropsMap = new HashMap();
            sipPropsMap.put("listenerName", listenerName);
            sipPropsMap.put("address", address);
            sipPropsMap.put("port", port);
            sipPropsMap.put("properties",
                (Map) handlerContext.getInputValue("AddProps"));
            sipPropsMap.put("enabled", enabled);
            sipPropsMap.put("transport", transport);
            handlerContext.getFacesContext().getExternalContext().getSessionMap()
                          .put("sipProps", sipPropsMap);

            //the actual creation is in step 2 of the wizard.
        } else {
            try {
                ObjectName sipListener = SipUtil.getSipListener(new ObjectName(
                            objectName), listenerName);

                HashMap attributeMap = new HashMap();
                attributeMap.put("port", handlerContext.getInputValue("Port"));
                attributeMap.put("address",
                    (String) handlerContext.getInputValue("Address"));
                attributeMap.put("transport",
                    (String) handlerContext.getInputValue("Transport"));
                attributeMap.put("enabled",
                    (Boolean) handlerContext.getInputValue("Listener"));
                SipUtil.setAttributeValues(sipListener, attributeMap);

                HashMap addProps = (HashMap) handlerContext.getInputValue(
                        "AddProps");
                ArrayList removeProps = (ArrayList) handlerContext.getInputValue(
                        "RemoveProps");
                SipUtil.setProperties(sipListener, addProps, removeProps);
            } catch (Exception ex) {
                GuiUtil.handleException(handlerContext, ex);
            }
        }
    }

    /**
     *  <p> The handler is called from the sip listener SSL edit and new screens. The handler gets the
     *  sip listener SSL properties if any in case of edit. In case of new, the handler sets the default
     *  sip listener SSL properties.</p>
     *  <p> Input value: "ObjectName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "ConfigName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Name"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Type"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Edit"   --Type: <code>java.lang.Boolean</code>
     *
     *  <p> Output value: "ClientAuth"   --Type: <code>java.lang.Boolean</code>
     *  <p> Output value: "CertNickname"   --Type: <code>java.lang.String</code>
     *  <p> Output value: "SSL3Prop"   --Type: <code>java.lang.Boolean</code>
     *  <p> Output value: "SSL2Prop"   --Type: <code>java.lang.Boolean</code>
     *  <p> Output value: "TLSProp"   --Type: <code>java.lang.Boolean</code>
     *  <p> Output value: "CommonCiphersList",    type=SelectItem[]
     *  <p> Output value: "EphemeralCiphersList", type=SelectItem[]
     *  <p> Output value: "OtherCiphersList",     type=SelectItem[]
     *  <p> Output value: "EccCiphersList",       type=SelectItem[]
     *  <p> Output value: "SelectedCommon"   --Type: <code>java.lang.String</code>[]
     *  <p> Output value: "SelectedEph"   --Type: <code>java.lang.String</code>[]
     *  <p> Output value: "SelectedOther"   --Type: <code>java.lang.String</code>[]
     *  <p> Output value: "SelectedEcc"   --Type: <code>java.lang.String</code>[]
     */
    @Handler(id = "getSipSSLProperties", input =  {
        @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "Name", type = String.class, required = true)
        , @HandlerInput(name = "Type", type = String.class, required = true)
        , @HandlerInput(name = "Edit", type = Boolean.class, required = true)
    }
    , output =  {
        @HandlerOutput(name = "ClientAuth", type = Boolean.class)
        , @HandlerOutput(name = "CertNickname", type = String.class)
        , @HandlerOutput(name = "SSL3Prop", type = Boolean.class)
        , @HandlerOutput(name = "SSL2Prop", type = Boolean.class)
        , @HandlerOutput(name = "TLSProp", type = Boolean.class)
        , @HandlerOutput(name = "CommonCiphersList", type = SelectItem[].class)
        , @HandlerOutput(name = "EphemeralCiphersList", type = SelectItem[].class)
        , @HandlerOutput(name = "OtherCiphersList", type = SelectItem[].class)
        , @HandlerOutput(name = "EccCiphersList", type = SelectItem[].class)
        , @HandlerOutput(name = "SelectedCommon", type = String[].class)
        , @HandlerOutput(name = "SelectedEph", type = String[].class)
        , @HandlerOutput(name = "SelectedOther", type = String[].class)
        , @HandlerOutput(name = "SelectedEcc", type = String[].class)
    }
    )
    public static void getSipSSLProperties(HandlerContext handlerContext) {
        String objectName = (String) handlerContext.getInputValue("ObjectName");
        String listenerName = ((String) handlerContext.getInputValue("Name"));
        String selectedCiphers = null;
        String type = (String) handlerContext.getInputValue("Type");

        boolean ssl3Prop = false;
        boolean ssl2Prop = false;
        boolean tlsProp = false;
        boolean clientAuth = false;
        boolean isEdit = ((Boolean) handlerContext.getInputValue("Edit")).booleanValue();

        Map sslProps = (Map) handlerContext.getFacesContext()
                                           .getExternalContext().getSessionMap()
                                           .get("sslProps");

        if (isEdit) {
            try {
                ObjectName ssl = SipUtil.getSSL(new ObjectName(objectName),
                        listenerName);

                if (ssl != null) {
                    HashMap sslAttrMap = SipUtil.getAttributeValues(ssl,
                            sslAttributeNames);

                    if ((sslAttrMap != null) && (sslAttrMap.size() > 0)) {
                        clientAuth = SipUtil.getBooleanValue(sslAttrMap.get(
                                    "client-auth-enabled"));
                        handlerContext.setOutputValue("CertNickname",
                            sslAttrMap.get("cert-nickname"));
                        ssl3Prop = SipUtil.getBooleanValue(sslAttrMap.get(
                                    "ssl3-enabled"));
                        ssl2Prop = SipUtil.getBooleanValue(sslAttrMap.get(
                                    "ssl2-enabled"));
                        tlsProp = SipUtil.getBooleanValue(sslAttrMap.get(
                                    "tls-enabled"));
                        selectedCiphers = (String) sslAttrMap.get(
                                "ssl3-tls-ciphers");
                    }
                }
            } catch (Exception ex) {
                GuiUtil.handleException(handlerContext, ex);
            }
        } else {
            if (sslProps != null) {
                clientAuth = (Boolean) sslProps.get("clientAuth");
                ssl3Prop = (Boolean) sslProps.get("ssl3Prop");
                ssl2Prop = (Boolean) sslProps.get("ssl2Prop");
                tlsProp = (Boolean) sslProps.get("tlsProp");
                handlerContext.setOutputValue("CertNickname",
                    sslProps.get("certNickname"));
            }
        }

        SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        String[] supportedCiphers = factory.getDefaultCipherSuites();
        Vector ciphers = getCiphersVector(supportedCiphers);

        SelectItem[] commonCiphers = ConfigurationHandlers.getOptions(getCommonCiphers(
                    ciphers));
        SelectItem[] ephemeralCiphers = ConfigurationHandlers.getOptions(getEphemeralCiphers(
                    ciphers));
        SelectItem[] otherCiphers = ConfigurationHandlers.getOptions(getOtherCiphers(
                    ciphers));
        SelectItem[] eccCiphers = ConfigurationHandlers.getOptions(getEccCiphers(
                    ciphers));

        handlerContext.setOutputValue("ClientAuth", clientAuth);
        handlerContext.setOutputValue("SSL3Prop", ssl3Prop);
        handlerContext.setOutputValue("SSL2Prop", ssl2Prop);
        handlerContext.setOutputValue("TLSProp", tlsProp);
        handlerContext.setOutputValue("CommonCiphersList", commonCiphers); //NOI18N
        handlerContext.setOutputValue("EphemeralCiphersList", ephemeralCiphers); //NOI18N
        handlerContext.setOutputValue("OtherCiphersList", otherCiphers); //NOI18N
        handlerContext.setOutputValue("EccCiphersList", eccCiphers); //NOI18N

        if (sslProps == null) {
            String[] ciphersArr = getSelectedCiphersList(selectedCiphers);
            Vector selValues = getCiphersVector(ciphersArr);
            handlerContext.setOutputValue("SelectedCommon",
                getCommonCiphers(selValues)); //NOI18N
            handlerContext.setOutputValue("SelectedEph",
                getEphemeralCiphers(selValues)); //NOI18N
            handlerContext.setOutputValue("SelectedOther",
                getOtherCiphers(selValues)); //NOI18N
            handlerContext.setOutputValue("SelectedEcc",
                getEccCiphers(selValues)); //NOI18N
        } else {
            handlerContext.setOutputValue("SelectedCommon",
                sslProps.get("selectedCommon")); //NOI18N
            handlerContext.setOutputValue("SelectedEph",
                sslProps.get("selectedEph")); //NOI18N
            handlerContext.setOutputValue("SelectedOther",
                sslProps.get("selectedOther")); //NOI18N
            handlerContext.setOutputValue("SelectedEcc",
                sslProps.get("selectedEcc")); //NOI18N
        }
    }

    /**
     *  <p> The handler saves the sip SSL properties for the sip listener. The function is called for
     *  both the edit as well as new sip listener. In case of new sip listener screen, the handler
     *  extracts the sip listener properties and creates a sip listener first. It then sets the SSL
     *  properties on the newly created listener.</p>
     *  <p> Input value: "ObjectName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "ConfigName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Name"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Type"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Edit"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "ClientAuth"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "CertNickname"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "SSL3Prop"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "SSL2Prop"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "TLSProp"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "CommonCiphersList",     type=SelectItem[]
     *  <p> Input value: "EphemeralCiphersList",  type=SelectItem[]
     *  <p> Input value: "OtherCiphersList",      type=SelectItem[]
     *  <p> Input value: "EccCiphersList",        type=SelectItem[]
     *  <p> Input value: "SelectedCommon"   --Type: <code>java.lang.String</code>[]
     *  <p> Input value: "SelectedEph"   --Type: <code>java.lang.String</code>[]
     *  <p> Input value: "SelectedOther"   --Type: <code>java.lang.String</code>[]
     *  <p> Input value: "SelectedEcc"   --Type: <code>java.lang.String</code>[]
     */
    @Handler(id = "saveSipSSLProperties", input =  {
        @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "Name", type = String.class, required = true)
        , @HandlerInput(name = "Type", type = String.class, required = true)
        , @HandlerInput(name = "Edit", type = Boolean.class, required = true)
        , @HandlerInput(name = "ClientAuth", type = Boolean.class)
        , @HandlerInput(name = "CertNickname", type = String.class)
        , @HandlerInput(name = "SSL3Prop", type = Boolean.class)
        , @HandlerInput(name = "SSL2Prop", type = Boolean.class)
        , @HandlerInput(name = "TLSProp", type = Boolean.class)
        , @HandlerInput(name = "CommonCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "EphemeralCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "OtherCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "EccCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "SelectedCommon", type = String[].class)
        , @HandlerInput(name = "SelectedEph", type = String[].class)
        , @HandlerInput(name = "SelectedOther", type = String[].class)
        , @HandlerInput(name = "SelectedEcc", type = String[].class)
    }
    )
    public static void saveSipSSLProperties(HandlerContext handlerContext) {
        try {
            String listenerName = (String) handlerContext.getInputValue("Name");
            String configName = (String) handlerContext.getInputValue(
                    "ConfigName");
            String objectName = (String) handlerContext.getInputValue(
                    "ObjectName");
            ObjectName ssl = null;
            ObjectName sipListener = null;
            String certNickname = (String) handlerContext.getInputValue(
                    "CertNickname");
            String type = (String) handlerContext.getInputValue("Type");

            boolean isEdit = ((Boolean) handlerContext.getInputValue("Edit")).booleanValue();

            if (isEdit) {
                // remove the ssl element from the listener.
                ssl = SipUtil.getSSL(new ObjectName(objectName), listenerName);
                sipListener = SipUtil.getSipListener(new ObjectName(objectName),
                        listenerName);

                if (ssl != null) {
                    //Remove the SSL element so that it can be recreated below
                    JMXUtil.invoke(sipListener, "removeSsl", null, null);
                    ssl = null;
                }
            } else {
                // New Listener. Need to create the listener and then set the SSL props
                Map props = (Map) handlerContext.getFacesContext()
                                                .getExternalContext()
                                                .getSessionMap().get("sipProps");
                AttributeList list = new AttributeList();
                list.add(new Attribute("id", props.get("listenerName")));
                list.add(new Attribute("port", props.get("port")));
                list.add(new Attribute("address", props.get("address")));
                list.add(new Attribute("transport", props.get("transport")));
                list.add(new Attribute("enabled", props.get("enabled")));

                Properties sipListenerProperties = new Properties();
                sipListenerProperties.putAll((Map) props.get("properties"));
                sipListener = (ObjectName) JMXUtil.invoke(new ObjectName(
                            objectName), "createSipListener",
                        new Object[] { list, sipListenerProperties, null },
                        new String[] {
                            list.getClass().getName(),
                            sipListenerProperties.getClass().getName(),
                            "java.lang.String"
                        });
            }

            if ((certNickname != null) && (!certNickname.equals(""))) {
                HashMap sslProps = new HashMap();

                if (ssl == null) {
                    //SSL Element for this listener does not exist create one
                    Attribute attribute = new Attribute("cert-nickname",
                            certNickname);
                    AttributeList attrList = new AttributeList(1);
                    attrList.add(attribute);
                    ssl = (ObjectName) JMXUtil.invoke(sipListener, "createSsl",
                            new Object[] { attrList },
                            new String[] { attrList.getClass().getName() });
                }

                boolean clientAuthEnabled = ((Boolean) handlerContext.getInputValue(
                        "ClientAuth")).booleanValue();
                boolean ssl3Prop = ((Boolean) handlerContext.getInputValue(
                        "SSL3Prop")).booleanValue();
                boolean ssl2Prop = ((Boolean) handlerContext.getInputValue(
                        "SSL2Prop")).booleanValue();
                boolean tlsProp = ((Boolean) handlerContext.getInputValue(
                        "TLSProp")).booleanValue();
                sslProps.put("cert-nickname", certNickname);
                sslProps.put("client-auth-enabled", clientAuthEnabled);
                sslProps.put("ssl2-enabled", ssl2Prop);
                sslProps.put("ssl3-enabled", ssl3Prop);
                sslProps.put("tls-enabled", tlsProp);

                if (ssl3Prop || tlsProp) {
                    SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
                    String[] supportedCiphers = factory.getDefaultCipherSuites();
                    Vector ciphersVector = getCiphersVector(supportedCiphers);
                    String[] selectedCiphers = getSelectedCiphersList((String) JMXUtil.getAttribute(
                                ssl, "ssl3-tls-ciphers"));
                    String[] selectedCommon = (String[]) handlerContext.getInputValue(
                            "SelectedCommon");
                    String[] selectedEph = (String[]) handlerContext.getInputValue(
                            "SelectedEph");
                    String[] selectedOther = (String[]) handlerContext.getInputValue(
                            "SelectedOther");
                    String[] selectedEcc = (String[]) handlerContext.getInputValue(
                            "SelectedEcc");

                    //TODO SSL Ciphers settings has issues. Has errors and does not save
                    // properly when selections are removed
                    String ciphers = processSelectedCiphers(selectedCommon, "");
                    ciphers = processSelectedCiphers(selectedEph, ciphers);
                    ciphers = processSelectedCiphers(selectedOther, ciphers);
                    ciphers = processSelectedCiphers(selectedEcc, ciphers);

                    sslProps.put("ssl3-tls-ciphers", ciphers);
                }

                SipUtil.setAttributeValues(ssl, sslProps);
            }
        } catch (Exception ex) {
            GuiUtil.handleException(handlerContext, ex);
        }
    }

    /**
     *  <p> The handler is called when a user clicks the previous button whilst creating a new sip
     *  listener. The handler sets the selected SSL properties into the sslProps map.</p>
     *  <p> Input value: "ClientAuth"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "CertNickname"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "SSL3Prop"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "SSL2Prop"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "TLSProp"   --Type: <code>java.lang.Boolean</code>
     *  <p> Input value: "CommonCiphersList",     type=SelectItem[]
     *  <p> Input value: "EphemeralCiphersList",  type=SelectItem[]
     *  <p> Input value: "OtherCiphersList",      type=SelectItem[]
     *  <p> Input value: "EccCiphersList",        type=SelectItem[]
     *  <p> Input value: "SelectedCommon"   --Type: <code>java.lang.String</code>[]
     *  <p> Input value: "SelectedEph"   --Type: <code>java.lang.String</code>[]
     *  <p> Input value: "SelectedOther"   --Type: <code>java.lang.String</code>[]
     *  <p> Input value: "SelectedEcc"   --Type: <code>java.lang.String</code>[]
     */
    @Handler(id = "updateSipSSLProperties", input =  {
        @HandlerInput(name = "ClientAuth", type = Boolean.class)
        , @HandlerInput(name = "CertNickname", type = String.class)
        , @HandlerInput(name = "SSL3Prop", type = Boolean.class)
        , @HandlerInput(name = "SSL2Prop", type = Boolean.class)
        , @HandlerInput(name = "TLSProp", type = Boolean.class)
        , @HandlerInput(name = "CommonCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "EphemeralCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "OtherCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "EccCiphersList", type = SelectItem[].class)
        , @HandlerInput(name = "SelectedCommon", type = String[].class)
        , @HandlerInput(name = "SelectedEph", type = String[].class)
        , @HandlerInput(name = "SelectedOther", type = String[].class)
        , @HandlerInput(name = "SelectedEcc", type = String[].class)
    }
    )
    public static void updateSipSSLProperties(HandlerContext handlerContext) {
        Map sslPropsMap = new HashMap();
        sslPropsMap.put("certNickname",
            (String) handlerContext.getInputValue("CertNickname"));
        sslPropsMap.put("clientAuth",
            ((Boolean) handlerContext.getInputValue("ClientAuth")).booleanValue());
        sslPropsMap.put("ssl3Prop",
            ((Boolean) handlerContext.getInputValue("SSL3Prop")).booleanValue());
        sslPropsMap.put("ssl2Prop",
            ((Boolean) handlerContext.getInputValue("SSL2Prop")).booleanValue());
        sslPropsMap.put("tlsProp",
            ((Boolean) handlerContext.getInputValue("TLSProp")).booleanValue());
        sslPropsMap.put("selectedCommon",
            (String[]) handlerContext.getInputValue("SelectedCommon"));
        sslPropsMap.put("selectedEph",
            (String[]) handlerContext.getInputValue("SelectedEph"));
        sslPropsMap.put("selectedOther",
            (String[]) handlerContext.getInputValue("SelectedOther"));
        sslPropsMap.put("selectedEcc",
            (String[]) handlerContext.getInputValue("SelectedEcc"));
        handlerContext.getFacesContext().getExternalContext().getSessionMap()
                      .put("sslProps", sslPropsMap);
    }

    /**
     *  <p> The handler deletes the selected sip listeners.</p>
     *  <p> Input value: "ObjectName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "selectedRows"   --Type: <code>java.util.List</code>
     *  <p> Input value: "ConfigName"   --Type: <code>java.lang.String</code>
     *  <p> Input value: "Type"   --Type: <code>java.lang.String</code>
     */
    @Handler(id = "deleteSipListeners", input =  {
        @HandlerInput(name = "ObjectName", type = String.class, required = true)
        , @HandlerInput(name = "selectedRows", type = List.class, required = true)
        , @HandlerInput(name = "ConfigName", type = String.class, required = true)
        , @HandlerInput(name = "Type", type = String.class, required = true)
    }
    )
    public static void deleteSipListeners(HandlerContext handlerContext) {
        String configName = (String) handlerContext.getInputValue("ConfigName");
        String objectName = (String) handlerContext.getInputValue("ObjectName");

        List obj = (List) handlerContext.getInputValue("selectedRows");
        String type = (String) handlerContext.getInputValue("Type");
        List<Map> selectedRows = (List) obj;

        try {
            for (Map oneRow : selectedRows) {
                String name = (String) oneRow.get("id");
                JMXUtil.invoke(objectName, "deleteSipListener",
                    new Object[] { name, null },
                    new String[] { "java.lang.String", "java.lang.String" });
            }
        } catch (Exception ex) {
            GuiUtil.handleException(handlerContext, ex);
        }
    }

    //Private/Protected members
    protected static String[] getSelectedCiphersList(String selectedCiphers) {
        Vector selItems = new Vector();

        if (selectedCiphers != null) {
            String[] sel = selectedCiphers.split(","); //NOI18N

            for (int i = 0; i < sel.length; i++) {
                String cName = sel[i];

                if (cName.startsWith("+")) { //NOI18N
                    cName = cName.substring(1, cName.length());
                    selItems.add(cName);
                }
            }
        }

        return (String[]) selItems.toArray(new String[selItems.size()]);
    }

    protected static String processSelectedCiphers(String[] selectedCiphers,
        String ciphers) {
        if (selectedCiphers != null) {
            for (int i = 0; i < selectedCiphers.length; i++) {
                if (!ciphers.equals("")) {
                    ciphers += ",";
                }

                ciphers += ("+" + selectedCiphers[i]);
            }
        }

        return ciphers;
    }

    protected static Vector getCiphersVector(String[] allCiphers) {
        Vector ciphers = new Vector();

        for (int i = 0; i < allCiphers.length; i++) {
            ciphers.add(allCiphers[i]);
        }

        return ciphers;
    }

    protected static String[] getCommonCiphers(Vector ciphers) {
        Vector commonCiphers = filterCiphers(ciphers, COMMON_CIPHERS);
        String[] ciphersList = (String[]) commonCiphers.toArray(new String[commonCiphers.size()]);
        ;

        return ciphersList;
    }

    protected static String[] getEccCiphers(Vector ciphers) {
        Vector eccCiphers = breakUpCiphers(new Vector(), ciphers, "ECDH"); //NOI18N
        eccCiphers = breakUpCiphers(eccCiphers, ciphers, "ECDHE"); //NOI18N

        String[] ciphersList = (String[]) eccCiphers.toArray(new String[eccCiphers.size()]);

        return ciphersList;
    }

    protected static String[] getEphemeralCiphers(Vector ciphers) {
        Vector ephmCiphers = breakUpCiphers(new Vector(), ciphers, "DHE_RSA"); //NOI18N
        ephmCiphers = breakUpCiphers(ephmCiphers, ciphers, "DHE_DSS"); //NOI18N

        String[] ciphersList = (String[]) ephmCiphers.toArray(new String[ephmCiphers.size()]);

        return ciphersList;
    }

    protected static String[] getOtherCiphers(Vector ciphers) {
        Vector bitCiphers = filterCiphers(ciphers, BIT_CIPHERS);
        String[] ciphersList = (String[]) bitCiphers.toArray(new String[bitCiphers.size()]);

        return ciphersList;
    }

    protected static Vector filterCiphers(Vector ciphers, String[] filterList) {
        Vector listCiphers = new Vector();

        for (int i = 0; i < ciphers.size(); i++) {
            String cipherName = ciphers.get(i).toString();

            if (Arrays.asList(filterList).contains(cipherName)) {
                listCiphers.add(ciphers.get(i));
            }
        }

        return listCiphers;
    }

    protected static Vector breakUpCiphers(Vector cipherSubset,
        Vector allCiphers, String type) {
        for (int i = 0; i < allCiphers.size(); i++) {
            String cipherName = allCiphers.get(i).toString();

            if (cipherName.indexOf(type) != -1) {
                if (!Arrays.asList(BIT_CIPHERS).contains(cipherName)) {
                    cipherSubset.add(cipherName);
                }
            }
        }

        return cipherSubset;
    }
}
