/**
 * Copyright (c) 2000/2001 Thomas Kopp
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
// $Id: SSLAdapter.java,v 1.4 2003/02/04 17:54:04 ylafon Exp $

package org.w3c.jigsaw.https;

import java.net.URL;
import java.net.MalformedURLException;

import org.w3c.util.ObservableProperties;
import org.w3c.jigsaw.daemon.ServerHandlerInitException;
import org.w3c.jigsaw.http.httpd;
import org.w3c.jigsaw.http.Request;
import org.w3c.jigsaw.https.socket.SSLSocketClientFactory;

import org.w3c.tools.resources.RequestInterface;
import org.w3c.tools.resources.ProtocolException;

/**
 * @author Thomas Kopp, Dialogika GmbH
 * @version 1.0.2, 8 April 2001
 * 
 * This class supplies a Jigsaw SSL daemon adapter
 * for enabling Jigsaw https support in accordance with the JSSE API
 * wrapping SSL features in order to solve multiple inheritance problems
 */
public class SSLAdapter {
    
    /**
     * flag for enabling debug output if applicable
     */
    private static boolean debug = false;

    /**
     * property key for enabling TLS support
     */
    public static final String SSL_ENABLED_P = "org.w3c.jigsaw.ssl.enabled";
    
    /**
     * flag indicating TLS support
     */
    private boolean ssl_enabled = false;
    
    /**
     * reference to the daemon in question
     */
    private httpd daemon = null;
    
    /**
     * uri of the daemon in question
     */
    private URL url = null;

    /**
     * constructor for a TLS support adapter
     * @param server reference to the daemon in question
     */
    public SSLAdapter(httpd server) {
        if (null != server) {
	    ssl_enabled = false;
	    daemon = server;
	    url = null;
        } else {
	    throw new NullPointerException("No daemon intance supplied for "+
					   " creating SSL adapter.");
	}
    }
    
    /**
     * method for initializing the properties of a daemon
     * @exception ServerHandlerInitException thrown if initialization fails
     */
    public void initializeProperties() 
        throws ServerHandlerInitException {
        ObservableProperties props = daemon.getProperties();
        boolean ssl_explicite = props.getBoolean(SSL_ENABLED_P, false);
        if (props.getBoolean(SSL_ENABLED_P, true) == ssl_explicite) {
           ssl_enabled = ssl_explicite;
        }
        else {
               // default to well-known factory if applicable        
    	       String factory_class = props.getString(httpd.CLIENT_FACTORY_P, 
						      null);
               if (null != factory_class) {
                  try {
                        Class factory = Class.forName(factory_class);
                        ssl_enabled = 
		      (SSLSocketClientFactory.class.isAssignableFrom(factory));
                  }
                  catch (Exception ex) {
                        if (debug) {
                           ex.printStackTrace();
                        }
                        ssl_enabled = false;
                  }
               }
               else ssl_enabled = false;
        }
        url = null;
    }

    /**
     * method for preparing a reply interface for a request
     * @param req the current request to be handled
     * @exception ProtocolException thrown if the request url is malformed
     */
    public void perform(RequestInterface req) 
	throws ProtocolException  {
	Request request = (Request)req;
        if (ssl_enabled) {
        
	    // set request protocol to https
	    URL url = request.getURL();
	    try {
		request.setURL(new URL("https", url.getHost(), url.getPort(),
				       url.getFile()));
	    } 
	    catch (MalformedURLException ex) {
		String error = "Bad url during switching to https.";
		daemon.errlog(error + " (" + ex.getMessage() + ")");
		if (debug) {
                    System.out.println(error);
                    ex.printStackTrace();
		}
		throw new ProtocolException(ex.getMessage());
	    }
	}
    }
    
    /**
     * method for supplying a daemon uri
     * @return uri of the daemon in question
     */
    public URL getURL() {
        if (url == null) {
	    if (ssl_enabled) {
		try {
		    if (daemon.getPort() != 443) {
			url = new URL("https", daemon.getHost(), 
				      daemon.getPort(), "/");
		    } else {
			url = new URL("https", daemon.getHost(), "/");
		    }
		}
		catch (MalformedURLException ex) {
		    if (debug) {
			ex.printStackTrace();
		    }
		    throw new RuntimeException("Unable to construct "+
					       "server uri. (" + 
					       ex.getMessage() + ")");
		}
	    } else {
		try {
		    if (daemon.getPort() != 80 ) {
			url = new URL("http", daemon.getHost(), 
				      daemon.getPort(), "/");
		    } else {
			url = new URL("http", daemon.getHost(), "/");
		    }
		} 
		catch (MalformedURLException ex) {
		    throw new RuntimeException("Unable to construct"+
					       " server uri. (" +
					       ex.getMessage() + ")");
		}
	    }
	}		
        return url;
    }
    
    /**
     * method for indicating TLS support
     * @return flag for indicating TLS support enabled
     */
    public boolean sslEnabled() {
	return ssl_enabled;
    }
}
