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}