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