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;
021import org.apache.hadoop.conf.Configuration;
022import org.apache.hadoop.util.ReflectionUtils;
023import org.apache.yetus.audience.InterfaceAudience;
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027/**
028 * Manages singleton instance of {@link VisibilityLabelService}
029 */
030@InterfaceAudience.Private
031public class VisibilityLabelServiceManager {
032
033  private static final Logger LOG = LoggerFactory.getLogger(VisibilityLabelServiceManager.class);
034
035  public static final String VISIBILITY_LABEL_SERVICE_CLASS =
036    "hbase.regionserver.visibility.label.service.class";
037  private static final VisibilityLabelServiceManager INSTANCE = new VisibilityLabelServiceManager();
038
039  private volatile VisibilityLabelService visibilityLabelService = null;
040  private String vlsClazzName = null;
041
042  private VisibilityLabelServiceManager() {
043
044  }
045
046  public static VisibilityLabelServiceManager getInstance() {
047    return INSTANCE;
048  }
049
050  /**
051   * n * @return singleton instance of {@link VisibilityLabelService}. The FQCN of the
052   * implementation class can be specified using
053   * "hbase.regionserver.visibility.label.service.class".
054   * @throws IOException When VLS implementation, as specified in conf, can not be loaded.
055   */
056  public VisibilityLabelService getVisibilityLabelService(Configuration conf) throws IOException {
057    String vlsClassName = conf.get(VISIBILITY_LABEL_SERVICE_CLASS,
058      DefaultVisibilityLabelServiceImpl.class.getCanonicalName()).trim();
059    if (this.visibilityLabelService != null) {
060      checkForClusterLevelSingleConf(vlsClassName);
061      return this.visibilityLabelService;
062    }
063    synchronized (this) {
064      if (this.visibilityLabelService != null) {
065        checkForClusterLevelSingleConf(vlsClassName);
066        return this.visibilityLabelService;
067      }
068      this.vlsClazzName = vlsClassName;
069      try {
070        this.visibilityLabelService =
071          (VisibilityLabelService) ReflectionUtils.newInstance(Class.forName(vlsClassName), conf);
072      } catch (ClassNotFoundException e) {
073        throw new IOException(e);
074      }
075      return this.visibilityLabelService;
076    }
077  }
078
079  private void checkForClusterLevelSingleConf(String vlsClassName) {
080    assert this.vlsClazzName != null;
081    if (!this.vlsClazzName.equals(vlsClassName)) {
082      LOG.warn("Trying to use table specific value for config "
083        + "'hbase.regionserver.visibility.label.service.class' which is not supported."
084        + " Will use the cluster level VisibilityLabelService class " + this.vlsClazzName);
085    }
086  }
087
088  /**
089   * @return singleton instance of {@link VisibilityLabelService}.
090   * @throws IllegalStateException if this called before initialization of singleton instance.
091   */
092  public VisibilityLabelService getVisibilityLabelService() {
093    // By the time this method is called, the singleton instance of visibilityLabelService should
094    // have been created. And it will be created as getVisibilityLabelService(Configuration conf)
095    // is called from VC#start() and that will be the 1st thing core code do with any CP.
096    if (this.visibilityLabelService == null) {
097      throw new IllegalStateException("VisibilityLabelService not yet instantiated");
098    }
099    return this.visibilityLabelService;
100  }
101}