001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security.visibility;
019
020import java.io.IOException;
021
022import org.apache.yetus.audience.InterfaceAudience;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.util.ReflectionUtils;
027
028/**
029 * Manages singleton instance of {@link VisibilityLabelService}
030 */
031@InterfaceAudience.Private
032public class VisibilityLabelServiceManager {
033
034  private static final Logger LOG = LoggerFactory.getLogger(VisibilityLabelServiceManager.class);
035
036  public static final String VISIBILITY_LABEL_SERVICE_CLASS =
037      "hbase.regionserver.visibility.label.service.class";
038  private static final VisibilityLabelServiceManager INSTANCE = new VisibilityLabelServiceManager();
039
040  private volatile VisibilityLabelService visibilityLabelService = null;
041  private String vlsClazzName = null;
042
043  private VisibilityLabelServiceManager() {
044
045  }
046
047  public static VisibilityLabelServiceManager getInstance() {
048    return INSTANCE;
049  }
050
051  /**
052   * @param conf
053   * @return singleton instance of {@link VisibilityLabelService}. The FQCN of the implementation
054   *         class can be specified using "hbase.regionserver.visibility.label.service.class".
055   * @throws IOException When VLS implementation, as specified in conf, can not be loaded.
056   */
057  public VisibilityLabelService getVisibilityLabelService(Configuration conf) throws IOException {
058    String vlsClassName = conf.get(VISIBILITY_LABEL_SERVICE_CLASS,
059        DefaultVisibilityLabelServiceImpl.class.getCanonicalName()).trim();
060    if (this.visibilityLabelService != null) {
061      checkForClusterLevelSingleConf(vlsClassName);
062      return this.visibilityLabelService;
063    }
064    synchronized (this) {
065      if (this.visibilityLabelService != null) {
066        checkForClusterLevelSingleConf(vlsClassName);
067        return this.visibilityLabelService;
068      }
069      this.vlsClazzName = vlsClassName;
070      try {
071        this.visibilityLabelService = (VisibilityLabelService) ReflectionUtils.newInstance(
072            Class.forName(vlsClassName), conf);
073      } catch (ClassNotFoundException e) {
074        throw new IOException(e);
075      }
076      return this.visibilityLabelService;
077    }
078  }
079
080  private void checkForClusterLevelSingleConf(String vlsClassName) {
081    assert this.vlsClazzName != null;
082    if (!this.vlsClazzName.equals(vlsClassName)) {
083      LOG.warn("Trying to use table specific value for config "
084          + "'hbase.regionserver.visibility.label.service.class' which is not supported."
085          + " Will use the cluster level VisibilityLabelService class " + this.vlsClazzName);
086    }
087  }
088
089  /**
090   * @return singleton instance of {@link VisibilityLabelService}.
091   * @throws IllegalStateException if this called before initialization of singleton instance.
092   */
093  public VisibilityLabelService getVisibilityLabelService() {
094    // By the time this method is called, the singleton instance of visibilityLabelService should
095    // have been created. And it will be created as getVisibilityLabelService(Configuration conf)
096    // is called from VC#start() and that will be the 1st thing core code do with any CP.
097    if (this.visibilityLabelService == null) {
098      throw new IllegalStateException("VisibilityLabelService not yet instantiated");
099    }
100    return this.visibilityLabelService;
101  }
102}