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.rest;
019
020import java.io.IOException;
021import org.apache.hadoop.conf.Configuration;
022import org.apache.hadoop.hbase.client.Admin;
023import org.apache.hadoop.hbase.client.Table;
024import org.apache.hadoop.hbase.filter.ParseFilter;
025import org.apache.hadoop.hbase.security.UserProvider;
026import org.apache.hadoop.hbase.util.ConnectionCache;
027import org.apache.hadoop.hbase.util.JvmPauseMonitor;
028import org.apache.hadoop.security.UserGroupInformation;
029import org.apache.hadoop.security.authorize.ProxyUsers;
030import org.apache.yetus.audience.InterfaceAudience;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034/**
035 * Singleton class encapsulating global REST servlet state and functions.
036 */
037@InterfaceAudience.Private
038public class RESTServlet implements Constants {
039  private static final Logger LOG = LoggerFactory.getLogger(RESTServlet.class);
040  private static RESTServlet INSTANCE;
041  private final Configuration conf;
042  private final MetricsREST metrics;
043  private final ConnectionCache connectionCache;
044  private final UserGroupInformation realUser;
045  private final JvmPauseMonitor pauseMonitor;
046
047  public static final String CLEANUP_INTERVAL = "hbase.rest.connection.cleanup-interval";
048  public static final String MAX_IDLETIME = "hbase.rest.connection.max-idletime";
049  static final String HBASE_REST_SUPPORT_PROXYUSER = "hbase.rest.support.proxyuser";
050
051  UserGroupInformation getRealUser() {
052    return realUser;
053  }
054
055  /** Returns the RESTServlet singleton instance */
056  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "MS_EXPOSE_REP",
057      justification = "singleton pattern")
058  public synchronized static RESTServlet getInstance() {
059    assert (INSTANCE != null);
060    return INSTANCE;
061  }
062
063  /** Returns the ConnectionCache instance */
064  public ConnectionCache getConnectionCache() {
065    return connectionCache;
066  }
067
068  /**
069   * @param conf         Existing configuration to use in rest servlet
070   * @param userProvider the login user provider
071   * @return the RESTServlet singleton instance
072   */
073  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "MS_EXPOSE_REP",
074      justification = "singleton pattern")
075  public synchronized static RESTServlet getInstance(Configuration conf, UserProvider userProvider)
076    throws IOException {
077    if (INSTANCE == null) {
078      INSTANCE = new RESTServlet(conf, userProvider);
079    }
080    return INSTANCE;
081  }
082
083  public synchronized static void stop() {
084    if (INSTANCE != null) {
085      INSTANCE.shutdown();
086      INSTANCE = null;
087    }
088  }
089
090  /**
091   * Constructor with existing configuration
092   * @param conf         existing configuration
093   * @param userProvider the login user provider
094   */
095  RESTServlet(final Configuration conf, final UserProvider userProvider) throws IOException {
096    this.realUser = userProvider.getCurrent().getUGI();
097    this.conf = conf;
098    registerCustomFilter(conf);
099
100    int cleanInterval = conf.getInt(CLEANUP_INTERVAL, 10 * 1000);
101    int maxIdleTime = conf.getInt(MAX_IDLETIME, 10 * 60 * 1000);
102    connectionCache = new ConnectionCache(conf, userProvider, cleanInterval, maxIdleTime);
103    if (supportsProxyuser()) {
104      ProxyUsers.refreshSuperUserGroupsConfiguration(conf);
105    }
106
107    metrics = new MetricsREST();
108
109    pauseMonitor = new JvmPauseMonitor(conf, metrics.getSource());
110    pauseMonitor.start();
111  }
112
113  Admin getAdmin() throws IOException {
114    return connectionCache.getAdmin();
115  }
116
117  /**
118   * Caller closes the table afterwards.
119   */
120  Table getTable(String tableName) throws IOException {
121    return connectionCache.getTable(tableName);
122  }
123
124  Configuration getConfiguration() {
125    return conf;
126  }
127
128  MetricsREST getMetrics() {
129    return metrics;
130  }
131
132  /**
133   * Helper method to determine if server should only respond to GET HTTP method requests.
134   * @return boolean for server read-only state
135   */
136  boolean isReadOnly() {
137    return getConfiguration().getBoolean("hbase.rest.readonly", false);
138  }
139
140  void setEffectiveUser(String effectiveUser) {
141    connectionCache.setEffectiveUser(effectiveUser);
142  }
143
144  /**
145   * Shutdown any services that need to stop
146   */
147  void shutdown() {
148    if (pauseMonitor != null) pauseMonitor.stop();
149    if (connectionCache != null) connectionCache.shutdown();
150  }
151
152  boolean supportsProxyuser() {
153    return conf.getBoolean(HBASE_REST_SUPPORT_PROXYUSER, false);
154  }
155
156  private void registerCustomFilter(Configuration conf) {
157    String[] filterList = conf.getStrings(Constants.CUSTOM_FILTERS);
158    if (filterList != null) {
159      for (String filterClass : filterList) {
160        String[] filterPart = filterClass.split(":");
161        if (filterPart.length != 2) {
162          LOG.warn("Invalid filter specification " + filterClass + " - skipping");
163        } else {
164          ParseFilter.registerFilter(filterPart[0], filterPart[1]);
165        }
166      }
167    }
168  }
169}