/*
 * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 * 
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package impl.java.dyn;

import java.dyn.MethodHandles;
import sun.reflect.Reflection;

/**
 * Access control to this package.
 * Classes in other packages can attempt to acquire the access token,
 * but will fail if they are not recognized as friends.
 * Certain methods in this package, although public, require a non-null
 * access token in order to proceed; they act like package-private methods.
 * @author jrose
 */

public class Access {
    private Access() { }

    /**
     * The heart of this pattern:  The list of classes which are
     * permitted to acquire the access token, and become honorary
     * members of this package.
     */
    static private final String[] FRIENDS = {
        "java.dyn.", "impl.java.dyn."
    };

    /**
     * The following object is NOT public.  That's the point of the pattern.
     * It is package-private, so that any member of this package
     * can acquire the access token, and give it away to trusted friends.
     */
    static final Access TOKEN = new Access();

    /**
     * @return Access.TOKEN, if the caller is a friend of this package
     */
    public static Access getToken() {
        Class<?> callc = Reflection.getCallerClass(2);
        if (callc.getClassLoader() == Access.class.getClassLoader()) {
            String callcName = callc.getName();
            for (String friend : FRIENDS) {
                if (callcName.startsWith(friend))
                    return TOKEN;
            }
        }
        throw new IllegalAccessError("bad caller: " + callc);
    }

    /**
     * Throw an IllegalAccessError if the caller does not possess
     * the Access.TOKEN.
     * @param must be Access.TOKEN
     */
    public static void check(Access token) {
        if (token == null)
            fail();
        // else it must be the unique Access.TOKEN
        assert(token == Access.TOKEN);
    }
    private static void fail() {
        Class<?> callc = Reflection.getCallerClass(3);
        throw new IllegalAccessError("bad caller: " + callc);
    }

    static {
        //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken");
    }
}
