/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 Bull S.A.
 * Contact: jonas-team@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
 *
 * Initial developer: Florent BENOIT
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.security.internal;

import javax.security.jacc.PolicyConfigurationFactory;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.jonas.lib.bootstrap.LoaderManager;
import org.ow2.jonas.lib.execution.ExecutionResult;
import org.ow2.jonas.lib.execution.IExecution;
import org.ow2.jonas.lib.execution.RunnableHelper;
import org.ow2.jonas.lib.security.jacc.JPolicy;
import org.ow2.jonas.lib.util.Log;


/**
 * Helper class for initializing the JACC provider
 * @author Florent Benoit
 */
public class PolicyProvider {

    /**
     * Only internal constructor, as it is an utility class
     */
    private PolicyProvider() {

    }

    /**
     * Logger which is used
     */
    private static Logger logger = null;

    /**
     * Init the JACC configuration
     * Defines in JACC Section 2
     * @throws SecurityException if JACC policy provider can not be set
     */
    public static void init() throws SecurityException {

        if (logger == null) {
            logger = Log.getLogger(Log.JONAS_SECURITY_PREFIX);
        }

        // Check if we have to use an existing policy provider
        // Section 2.7

        String javaPolicy = System.getProperty("javax.security.jacc.policy.provider");

        LoaderManager lm = LoaderManager.getInstance();
        ClassLoader externalLoader = null;
        try {
            externalLoader = lm.getExternalLoader();
        } catch (Exception e) {
            throw new SecurityException("cannot get  Commonsloader: " + e);
        }

        if (javaPolicy != null) {
            try {
                java.security.Policy policy = (java.security.Policy) externalLoader.loadClass(javaPolicy).newInstance();
                java.security.Policy.setPolicy(policy);
            } catch (ClassNotFoundException cnfe) {
                // problem with property value of classpath
                throw new SecurityException(cnfe.getMessage());
            } catch (IllegalAccessException iae) {
                // problem with policy class definition
                throw new SecurityException(iae.getMessage());
            } catch (InstantiationException ie) {
                // problem with policy instantiation
                throw new SecurityException(ie.getMessage());
            } catch (ClassCastException cce) {
                // Not instance of java.security.policy
                throw new SecurityException(cce.getMessage());
            } catch (Exception e) {
                // cannot load policy
                throw new SecurityException("cannot load security policy: " + e);
            }
            logger.log(BasicLevel.INFO, "Using policy provider '" + javaPolicy + "'");
        }

        // Defines the JOnAS JACC provider if no provider is already defined
        // Section 2.3
        String jaccFactoryProvider = System.getProperty("javax.security.jacc.PolicyConfigurationFactory.provider");
        if (jaccFactoryProvider == null) {
            logger.log(BasicLevel.INFO, "Using JOnAS PolicyConfigurationFactory provider and JOnAS Policy provider");
            System.setProperty("javax.security.jacc.PolicyConfigurationFactory.provider",
                    "org.ow2.jonas.lib.security.jacc.PolicyConfigurationFactoryWrapper");
            // Add the JOnAS delegating policy provider
            java.security.Policy.setPolicy(JPolicy.getInstance());
        } else {
            logger.log(BasicLevel.INFO, "Using factory '" + jaccFactoryProvider
                    + "' as PolicyConfigurationFactory provider");
        }

        // Init JACC
        // -------------------------------------------


        IExecution<Void> exec = new IExecution<Void>() {
            public Void execute() throws Exception {
                PolicyConfigurationFactory.getPolicyConfigurationFactory();
                return null;
            }
        };

        // Execute

        ExecutionResult<Void> result = RunnableHelper.execute(externalLoader, exec);

         // Throw a SecurityException if something was wrong
        if (result.hasException()) {
            Exception e = result.getException();
            throw new SecurityException("Error when trying to get the PolicyConfigurationFactory object : '"
                    + e.getMessage() + "'.", e);

        }

        // TODO : Register Context Handler


    }

}
