content: /*
   * 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.cassandra.auth;
  
  import java.util.Set;
  
  import com.google.common.base.Objects;
  import com.google.common.collect.Sets;
  import org.apache.commons.lang3.StringUtils;
  
  import org.apache.cassandra.config.DatabaseDescriptor;
  
  /**
   * IResource implementation representing database roles.
   *
   * The root level "roles" resource represents the collection of all Roles.
   * Individual roles are represented as members of the collection:
   * "roles"                    - the root level collection resource
   * "roles/role1"              - a specific database role
   */
  public class RoleResource implements IResource, Comparable<RoleResource>
  {
      enum Level
      {
          ROOT, ROLE
      }
  
      // permissions which may be granted on the root level resource
      private static final Set<Permission> ROOT_LEVEL_PERMISSIONS = Sets.immutableEnumSet(Permission.CREATE,
                                                                                          Permission.ALTER,
                                                                                          Permission.DROP,
                                                                                          Permission.AUTHORIZE,
                                                                                          Permission.DESCRIBE);
      // permissions which may be granted on role level resources
      private static final Set<Permission> ROLE_LEVEL_PERMISSIONS = Sets.immutableEnumSet(Permission.ALTER,
                                                                                          Permission.DROP,
                                                                                          Permission.AUTHORIZE,
                                                                                          Permission.DESCRIBE);
  
      private static final String ROOT_NAME = "roles";
      private static final RoleResource ROOT_RESOURCE = new RoleResource();
  
      private final Level level;
      private final String name;
  
      private RoleResource()
      {
          level = Level.ROOT;
          name = null;
      }
  
      private RoleResource(String name)
      {
          level = Level.ROLE;
          this.name = name;
      }
  
      /**
       * @return the root-level resource.
       */
      public static RoleResource root()
      {
          return ROOT_RESOURCE;
      }
  
      /**
       * Creates a RoleResource representing an individual Role.
       * @param name name of the Role.
       * @return RoleResource instance reresenting the Role.
       */
      public static RoleResource role(String name)
      {
          return new RoleResource(name);
      }
  
      /**
       * Parses a role resource name into a RoleResource instance.
       *
       * @param name Name of the data resource.
       * @return RoleResource instance matching the name.
       */
      public static RoleResource fromName(String name)
      {
          String[] parts = StringUtils.split(name, "/", 2);
  
          if (!parts[0].equals(ROOT_NAME))
              throw new IllegalArgumentException(String.format("%s is not a valid role resource name", name));
  
          if (parts.length == 1)
              return root();
  
          return role(parts[1]);
      }
  
      /**
       * @return Printable name of the resource.
       */
      public String getName()
      {
          return level == Level.ROOT ? ROOT_NAME : String.format("%s/%s", ROOT_NAME, name);
      }
  
      /**
       * @return short form name of a role level resource. i.e. not the full "root/name" version returned by getName().
       * Throws IllegalStateException if called on the root-level resource.
       */
      public String getRoleName()
      {
          if (level == Level.ROOT)
              throw new IllegalStateException(String.format("%s role resource has no role name", level));
          return name;
      }
  
      /**
       * @return Parent of the resource, if any. Throws IllegalStateException if it's the root-level resource.
       */
      public IResource getParent()
      {
          if (level == Level.ROLE)
              return root();
  
          throw new IllegalStateException("Root-level resource can't have a parent");
      }
  
      public boolean hasParent()
      {
          return level != Level.ROOT;
      }
  
      public boolean exists()
      {
          return level == Level.ROOT || DatabaseDescriptor.getRoleManager().isExistingRole(this);
      }
  
      public Set<Permission> applicablePermissions()
      {
          return level == Level.ROOT ? ROOT_LEVEL_PERMISSIONS : ROLE_LEVEL_PERMISSIONS;
      }
  
      public int compareTo(RoleResource o)
      {
          return this.name.compareTo(o.name);
      }
  
      @Override
      public String toString()
      {
          return level == Level.ROOT ? "<all roles>" : String.format("<role %s>", name);
      }
  
      @Override
      public boolean equals(Object o)
      {
          if (this == o)
              return true;
  
          if (!(o instanceof RoleResource))
              return false;
  
          RoleResource rs = (RoleResource) o;
  
          return Objects.equal(level, rs.level) && Objects.equal(name, rs.name);
      }
  
      @Override
      public int hashCode()
      {
          return Objects.hashCode(level, name);
      }
  }
  