gt:             synchronized (permissions) {
context: /*
   * Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package java.security;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Enumeration;
  import java.util.List;
  import java.util.Map;
  import java.util.WeakHashMap;
  import sun.misc.JavaSecurityProtectionDomainAccess;
  import static sun.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache;
  import sun.misc.SharedSecrets;
  import sun.security.util.Debug;
  import sun.security.util.SecurityConstants;
  import sun.misc.JavaSecurityAccess;
  import sun.misc.SharedSecrets;
  
  /**
   *
   *<p>
   * This ProtectionDomain class encapsulates the characteristics of a domain,
   * which encloses a set of classes whose instances are granted a set
   * of permissions when being executed on behalf of a given set of Principals.
   * <p>
   * A static set of permissions can be bound to a ProtectionDomain when it is
   * constructed; such permissions are granted to the domain regardless of the
   * Policy in force. However, to support dynamic security policies, a
   * ProtectionDomain can also be constructed such that it is dynamically
   * mapped to a set of permissions by the current Policy whenever a permission
   * is checked.
   * <p>
   *
   * @author Li Gong
   * @author Roland Schemers
   * @author Gary Ellison
   */
  
  public class ProtectionDomain {
  
      static {
          // Set up JavaSecurityAccess in SharedSecrets
          SharedSecrets.setJavaSecurityAccess(
              new JavaSecurityAccess() {
                  public <T> T doIntersectionPrivilege(
                      PrivilegedAction<T> action,
                      final AccessControlContext stack,
                      final AccessControlContext context)
                  {
                      if (action == null) {
                          throw new NullPointerException();
                      }
                      return AccessController.doPrivileged(
                          action,
                          new AccessControlContext(
                              stack.getContext(), context).optimize()
                      );
                  }
  
                  public <T> T doIntersectionPrivilege(
                      PrivilegedAction<T> action,
                      AccessControlContext context)
                  {
                      return doIntersectionPrivilege(action,
                          AccessController.getContext(), context);
                  }
              }
         );
      }
  
      /* CodeSource */
      private CodeSource codesource ;
  
      /* [IKVM] If this is a protection from an Assembly class loader, we lazily construct the codesource, classloader and permissions */
      private cli.System.Reflection.Assembly assembly;
  
      /* ClassLoader the protection domain was consed from */
      private ClassLoader classloader;
  
      /* Principals running-as within this protection domain */
      private Principal[] principals;
  
      /* the rights this protection domain is granted */
      private PermissionCollection permissions;
  
      /* if the permissions object has AllPermission */
      private boolean hasAllPerm = false;
  
      /* the PermissionCollection is static (pre 1.4 constructor)
         or dynamic (via a policy refresh) */
      private boolean staticPermissions;
  
      /*
       * An object used as a key when the ProtectionDomain is stored in a Map.
       */
      final Key key = new Key();
  
      /* [IKVM] constructor for use by the runtime (AssemblyClassLoader) */
      ProtectionDomain(cli.System.Reflection.Assembly assembly) {
          this.assembly = assembly;
          this.hasAllPerm = true;
          this.staticPermissions = true;
          this.principals = new Principal[0];
      }
  
      /* [IKVM] */
      private void lazyInitClassLoader() {
          if (classloader == null && assembly != null) {
              classloader = ikvm.runtime.AssemblyClassLoader.getAssemblyClassLoader(assembly);
          }
      }
  
      /* [IKVM] */
      private void lazyInitPermissions() {
          if (permissions == null && hasAllPerm) {
              Permissions p = new Permissions();
              p.add(new AllPermission());
              p.setReadOnly();
              // we lock on principals since that is a private object
              synchronized (principals) {
                  if (permissions == null) {
                      permissions = p;
                  }
              }
          }
      }
  
      /* [IKVM] */
      private void lazyInitCodeSource() {
          if (codesource == null && assembly != null) {
              java.net.URL url;
              try {
                  if (false) throw new cli.System.NotSupportedException();
                  url = new java.net.URL(assembly.get_EscapedCodeBase());
              } catch (java.net.MalformedURLException _) {
                  url = null;
              } catch (cli.System.NotSupportedException _) {
                  // dynamic assemblies don't have a codebase
                  url = null;
              }
              CodeSource cs = new CodeSource(url, (java.security.cert.Certificate[])null);
              // we lock on principals since that is a private object
              synchronized (principals) {
                  if (codesource == null) {
                      codesource = cs;
                  }
              }
          }
      }
  
      /**
       * Creates a new ProtectionDomain with the given CodeSource and
       * Permissions. If the permissions object is not null, then
       *  <code>setReadOnly())</code> will be called on the passed in
       * Permissions object. The only permissions granted to this domain
       * are the ones specified; the current Policy will not be consulted.
       *
       * @param codesource the codesource associated with this domain
       * @param permissions the permissions granted to this domain
       */
      public ProtectionDomain(CodeSource codesource,
                              PermissionCollection permissions) {
          this.codesource = codesource;
          if (permissions != null) {
              this.permissions = permissions;
              this.permissions.setReadOnly();
              if (permissions instanceof Permissions &&
                  ((Permissions)permissions).allPermission != null) {
                  hasAllPerm = true;
              }
          }
          this.classloader = null;
          this.principals = new Principal[0];
          staticPermissions = true;
      }
  
      /**
       * Creates a new ProtectionDomain qualified by the given CodeSource,
       * Permissions, ClassLoader and array of Principals. If the
       * permissions object is not null, then <code>setReadOnly()</code>
       * will be called on the passed in Permissions object.
       * The permissions granted to this domain are dynamic; they include
       * both the static permissions passed to this constructor, and any
       * permissions granted to this domain by the current Policy at the
       * time a permission is checked.
       * <p>
       * This constructor is typically used by
       * {@link SecureClassLoader ClassLoaders}
       * and {@link DomainCombiner DomainCombiners} which delegate to
       * <code>Policy</code> to actively associate the permissions granted to
       * this domain. This constructor affords the
       * Policy provider the opportunity to augment the supplied
       * PermissionCollection to reflect policy changes.
       * <p>
       *
       * @param codesource the CodeSource associated with this domain
       * @param permissions the permissions granted to this domain
       * @param classloader the ClassLoader associated with this domain
       * @param principals the array of Principals associated with this
       * domain. The contents of the array are copied to protect against
       * subsequent modification.
       * @see Policy#refresh
       * @see Policy#getPermissions(ProtectionDomain)
       * @since 1.4
       */
      public ProtectionDomain(CodeSource codesource,
                              PermissionCollection permissions,
                              ClassLoader classloader,
                              Principal[] principals) {
          this.codesource = codesource;
          if (permissions != null) {
              this.permissions = permissions;
              this.permissions.setReadOnly();
              if (permissions instanceof Permissions &&
                  ((Permissions)permissions).allPermission != null) {
                  hasAllPerm = true;
              }
          }
          this.classloader = classloader;
          this.principals = (principals != null ? principals.clone():
                             new Principal[0]);
          staticPermissions = false;
      }
  
      /**
       * Returns the CodeSource of this domain.
       * @return the CodeSource of this domain which may be null.
       * @since 1.2
       */
      public final CodeSource getCodeSource() {
          lazyInitCodeSource();
          return this.codesource;
      }
  
  
      /**
       * Returns the ClassLoader of this domain.
       * @return the ClassLoader of this domain which may be null.
       *
       * @since 1.4
       */
      public final ClassLoader getClassLoader() {
          lazyInitClassLoader();
          return this.classloader;
      }
  
  
      /**
       * Returns an array of principals for this domain.
       * @return a non-null array of principals for this domain.
       * Returns a new array each time this method is called.
       *
       * @since 1.4
       */
      public final Principal[] getPrincipals() {
          return this.principals.clone();
      }
  
      /**
       * Returns the static permissions granted to this domain.
       *
       * @return the static set of permissions for this domain which may be null.
       * @see Policy#refresh
       * @see Policy#getPermissions(ProtectionDomain)
       */
      public final PermissionCollection getPermissions() {
          lazyInitPermissions();
          return permissions;
      }
  
      /**
       * Check and see if this ProtectionDomain implies the permissions
       * expressed in the Permission object.
       * <p>
       * The set of permissions evaluated is a function of whether the
       * ProtectionDomain was constructed with a static set of permissions
       * or it was bound to a dynamically mapped set of permissions.
       * <p>
       * If the ProtectionDomain was constructed to a
       * {@link #ProtectionDomain(CodeSource, PermissionCollection)
       * statically bound} PermissionCollection then the permission will
       * only be checked against the PermissionCollection supplied at
       * construction.
       * <p>
       * However, if the ProtectionDomain was constructed with
       * the constructor variant which supports
       * {@link #ProtectionDomain(CodeSource, PermissionCollection,
       * ClassLoader, java.security.Principal[]) dynamically binding}
       * permissions, then the permission will be checked against the
       * combination of the PermissionCollection supplied at construction and
       * the current Policy binding.
       * <p>
       *
       * @param permission the Permission object to check.
       *
       * @return true if "permission" is implicit to this ProtectionDomain.
       */
      public boolean implies(Permission permission) {
  
          if (hasAllPerm) {
              // internal permission collection already has AllPermission -
              // no need to go to policy
              return true;
          }
  
          if (!staticPermissions &&
              Policy.getPolicyNoCheck().implies(this, permission))
              return true;
          if (permissions != null)
              return permissions.implies(permission);
  
          return false;
      }
  
      /**
       * Convert a ProtectionDomain to a String.
       */
      @Override public String toString() {
          lazyInitCodeSource();
          lazyInitClassLoader();
          String pals = "<no principals>";
          if (principals != null && principals.length > 0) {
              StringBuilder palBuf = new StringBuilder("(principals ");
  
              for (int i = 0; i < principals.length; i++) {
                  palBuf.append(principals[i].getClass().getName() +
                              " \"" + principals[i].getName() +
                              "\"");
                  if (i < principals.length-1)
                      palBuf.append(",\n");
                  else
                      palBuf.append(")\n");
              }
              pals = palBuf.toString();
          }
  
          // Check if policy is set; we don't want to load
          // the policy prematurely here
          PermissionCollection pc = Policy.isSet() && seeAllp() ?
                                        mergePermissions():
                                        getPermissions();
  
          return "ProtectionDomain "+
              " "+codesource+"\n"+
              " "+classloader+"\n"+
              " "+pals+"\n"+
              " "+pc+"\n";
      }
  
      /**
       * Return true (merge policy permissions) in the following cases:
       *
       * . SecurityManager is null
       *
       * . SecurityManager is not null,
       *          debug is not null,
       *          SecurityManager impelmentation is in bootclasspath,
       *          Policy implementation is in bootclasspath
       *          (the bootclasspath restrictions avoid recursion)
       *
       * . SecurityManager is not null,
       *          debug is null,
       *          caller has Policy.getPolicy permission
       */
      private static boolean seeAllp() {
          SecurityManager sm = System.getSecurityManager();
  
          if (sm == null) {
              return true;
          } else {
              Debug debug = Debug.getInstance("domain");
              if (debug != null) {
                  if (sm.getClass().getClassLoader() == null &&
                      Policy.getPolicyNoCheck().getClass().getClassLoader()
                                                                  == null) {
                      return true;
                  }
              } else {
                  try {
                      sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
                      return true;
                  } catch (SecurityException se) {
                      // fall thru and return false
                  }
              }
          }
  
          return false;
      }
  
      private PermissionCollection mergePermissions() {
          lazyInitPermissions();
          if (staticPermissions)
              return permissions;
  
          PermissionCollection perms =
              java.security.AccessController.doPrivileged
              (new java.security.PrivilegedAction<PermissionCollection>() {
                      public PermissionCollection run() {
                          Policy p = Policy.getPolicyNoCheck();
                          return p.getPermissions(ProtectionDomain.this);
                      }
                  });
  
          Permissions mergedPerms = new Permissions();
          int swag = 32;
          int vcap = 8;
          Enumeration<Permission> e;
          List<Permission> pdVector = new ArrayList<>(vcap);
          List<Permission> plVector = new ArrayList<>(swag);
  
          //
          // Build a vector of domain permissions for subsequent merge
          if (permissions != null) {
  