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}