/*
 *  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.harmony.luni.util;


import java.lang.reflect.AccessibleObject;
import java.security.Policy;
import java.security.PrivilegedAction;
import java.security.Security;

/**
 * Helper class to avoid multiple anonymous inner class for
 * <code>{@link java.security.AccessController#doPrivileged(PrivilegedAction)}</code>
 * calls.
 */
public class PriviAction<T> implements PrivilegedAction<T> {

    private Object arg1;

    private Object arg2;

    private int action;

    private static final int GET_SYSTEM_PROPERTY = 1;

    private static final int GET_SECURITY_POLICY = 2;

    private static final int SET_ACCESSIBLE = 3;

    private static final int GET_SECURITY_PROPERTY = 4;

    /**
     * Creates a PrivilegedAction to get the security property with the given
     * name.
     *
     * @param property
     *            the name of the property
     *
     * @see Security#getProperty
     */
    public static PrivilegedAction<String> getSecurityProperty(String property) {
        return new PriviAction<String>(GET_SECURITY_PROPERTY, property);
    }

    private PriviAction(int action, Object arg) {
        this.action = action;
        this.arg1 = arg;
    }

    /**
     * Creates a PrivilegedAction to get the current security policy object.
     *
     * @see Policy#getPolicy
     */
    public PriviAction() {
        action = GET_SECURITY_POLICY;
    }

    /**
     * Creates a PrivilegedAction to disable the access checks to the given
     * object.
     *
     * @param object
     *            the object whose accessible flag will be set to
     *            <code>true</code>
     *
     * @see AccessibleObject#setAccessible(boolean)
     */
    public PriviAction(AccessibleObject object) {
        action = SET_ACCESSIBLE;
        arg1 = object;
    }

    /**
     * Creates a PrivilegedAction to return the value of the system property
     * with the given key.
     *
     * @param property
     *            the key of the system property
     *
     * @see System#getProperty(String)
     */
    public PriviAction(String property) {
        action = GET_SYSTEM_PROPERTY;
        arg1 = property;
    }

    /**
     * Creates a PrivilegedAction to return the value of the system property
     * with the given key.
     *
     * @param property
     *            the key of the system property
     * @param defaultAnswer
     *            the return value if the system property does not exist
     *
     * @see System#getProperty(String, String)
     */
    public PriviAction(String property, String defaultAnswer) {
        action = GET_SYSTEM_PROPERTY;
        arg1 = property;
        arg2 = defaultAnswer;
    }

    /**
     * Performs the actual privileged computation as defined by the constructor.
     *
     * @see java.security.PrivilegedAction#run()
     */
    @SuppressWarnings("unchecked")
    public T run() {
        switch (action) {
        case GET_SYSTEM_PROPERTY:
            return (T)System.getProperty((String) arg1, (String) arg2);
        case GET_SECURITY_PROPERTY:
            return (T)Security.getProperty((String) arg1);
        case GET_SECURITY_POLICY:
            return (T)Policy.getPolicy();
        case SET_ACCESSIBLE:
            ((AccessibleObject) arg1).setAccessible(true);
        }
        return null;
    }
}
