org.frameworkset.spi.remote.http.proxy.HttpServiceHosts Maven / Gradle / Ivy
Show all versions of bboss-http Show documentation
package org.frameworkset.spi.remote.http.proxy;
/**
* Copyright 2008 biaoping.yin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.commons.codec.binary.Base64;
import org.frameworkset.spi.assemble.GetProperties;
import org.frameworkset.spi.remote.http.ClientConfiguration;
import org.frameworkset.spi.remote.http.HttpHost;
import org.frameworkset.spi.remote.http.proxy.route.RoutingFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
*
Description:
*
* Copyright (c) 2018
* date 2019/6/17 19:08
* @author biaoping.yin
* @version 1.0
*/
public class HttpServiceHosts {
private static final Logger logger = LoggerFactory.getLogger(HttpServiceHosts.class);
public HttpServiceHostsConfig getHttpServiceHostsConfig() {
return httpServiceHostsConfig;
}
private final HttpServiceHostsConfig httpServiceHostsConfig;
private ExceptionWare exceptionWare;
private HttpHostDiscover hostDiscover;
// private Map authHeaders;
protected RoundRobinList serversList;
protected List addressList;
private HealthCheck healthCheck;
private Map addressMap ;
private String routing;
private RoutingFilter routingFilter;
private final ReadWriteLock routingFilterLock = new ReentrantReadWriteLock();
private final Lock routingFilterReadLock = routingFilterLock.readLock();
private final Lock routingFilterWriteLock = routingFilterLock.writeLock();
private ClientConfiguration clientConfiguration;
public HttpServiceHosts(){
httpServiceHostsConfig = new HttpServiceHostsConfig();
}
/**
* 如果没有启动health健康检查机制,将启用被动自恢复机制
*/
private boolean healthCheckStarted;
public boolean isFailAllContinue() {
return failAllContinue;
}
public void setFailAllContinue(boolean failAllContinue) {
this.failAllContinue = failAllContinue;
}
private boolean failAllContinue = true;
public boolean healthCheckStarted(){
return healthCheckStarted;
}
public HttpAddress getHttpAddress(){
HttpAddress httpAddress = null;
if(!hasRouting) {
httpAddress = serversList.get();
if(httpAddress == null && (failAllContinue || !this.healthCheckStarted)){
httpAddress = serversList.getOkOrFailed();
}
if(httpAddress == null) {
String message = new StringBuilder().append("All Http Server ").append(serversList.toString()).append(" can't been connected.").toString();
throw new NoHttpServerException(message);
}
}
else{
routingFilterReadLock.lock();
try {
httpAddress = this.routingFilter.get();
if(httpAddress == null && !this.healthCheckStarted){
httpAddress = this.routingFilter.getOkOrFailed();
}
if(httpAddress == null) {
String message = new StringBuilder().append("All Http Server ").append(routingFilter.toString()).append(" can't been connected.").toString();
throw new NoHttpServerException(message);
}
}
finally {
routingFilterReadLock.unlock();
}
}
return httpAddress;
}
public boolean reachEnd(int tryCount){
if(!hasRouting) {
return tryCount >= serversList.size() - 1;
}
else{
routingFilterReadLock.lock();
try {
return tryCount >= routingFilter.size() - 1;
}
finally {
routingFilterReadLock.unlock();
}
}
}
public static String getHeader(String user, String password) {
String auth = user + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
return "Basic " + new String(encodedAuth);
}
public void after(String httpPoolName, GetProperties context){
// if(hosts != null && !hosts.trim().equals(""))
addressList = new ArrayList();
addressMap = new HashMap();
if(httpServiceHostsConfig.getHosts() != null && !httpServiceHostsConfig.getHosts().trim().equals("")) {
String[] hostNames = httpServiceHostsConfig.getHosts().split(",");
for (String host : hostNames) {
HttpAddress esAddress = new HttpAddress(host.trim(), httpServiceHostsConfig.getHealth());
addressList.add(esAddress);
addressMap.put(esAddress.getAddress(), esAddress);
}
//第一次强制分组
routingGroup(false,null);
}
serversList = new RoundRobinList(this,addressList);
// if (httpServiceHostsConfig.getAuthAccount() != null && !httpServiceHostsConfig.getAuthAccount().equals("")) {
// authHeaders = new HashMap();
// authHeaders.put("Authorization", getHeader(httpServiceHostsConfig.getAuthAccount(), httpServiceHostsConfig.getAuthPassword()));
// }
if(httpServiceHostsConfig.getExceptionWare() != null){
try {
Class exceptionWareClass = (Class) Class.forName(httpServiceHostsConfig.getExceptionWare().trim());
ExceptionWare exceptionWare_ = exceptionWareClass.newInstance();
exceptionWare_.setHttpServiceHosts(this);
this.exceptionWare = exceptionWare_;
}
catch (Exception e){
if(logger.isErrorEnabled()) {
logger.error(new StringBuilder().append(" Http pool[")
.append(getClientConfiguration().getBeanName()).append("]")
.append(" ExceptionWare init failed:").toString(), e);
}
}
}
else if(this.exceptionWare != null){
exceptionWare.setHttpServiceHosts(this);
}
if(httpServiceHostsConfig.getHealthCheckInterval() > 0 && httpServiceHostsConfig.getHealth() != null && !this.httpServiceHostsConfig.getHealth().equals("")) {
if(logger.isInfoEnabled()) {
logger.info(new StringBuilder().append("Start Http pool[")
.append(getClientConfiguration().getBeanName()).append("]")
.append(" HttpProxy server healthCheck thread,you can set http.healthCheckInterval=-1 in config file to disable healthCheck.").toString());
}
healthCheck = new HealthCheck(httpPoolName,addressList, httpServiceHostsConfig.getHealthCheckInterval());
healthCheck.run();
healthCheckStarted = true;
}
else {
if(logger.isInfoEnabled()) {
logger.info(new StringBuilder().append("HttpProxy server Http pool[")
.append(getClientConfiguration().getBeanName()).append("]")
.append(" healthCheck is disabled,you can set HttpProxy http.healthCheckInterval (>0) and http.health in configfile to enabled healthCheck.").toString());
}
}
if(httpServiceHostsConfig.getDiscoverService() != null && !this.httpServiceHostsConfig.getDiscoverService().equals("")) {
logger.info(new StringBuilder().append("Start Http pool[")
.append(getClientConfiguration().getBeanName()).append("]")
.append(" discoverHost thread,to distabled set http.discoverService to null in configfile.").toString());
try {
Class httpHostDiscoverClass = (Class) Class.forName(this.httpServiceHostsConfig.getDiscoverService());
HttpHostDiscover hostDiscover = httpHostDiscoverClass.newInstance();
hostDiscover.setHttpServiceHosts(this);
hostDiscover.start();
this.hostDiscover = hostDiscover;
}
catch (Exception e){
if(logger.isErrorEnabled()) {
logger.error(new StringBuilder().append("Start Http pool[")
.append(getClientConfiguration().getBeanName()).append("]").append(" discovery service failed:").toString(), e);
}
}
}
else if(hostDiscover == null){
logger.info(new StringBuilder().append("Discover Http pool[")
.append(getClientConfiguration().getBeanName()).append("]").append(" is disabled,to enabled set http.discoverService in configfile.").toString());
}
else{
hostDiscover.setHttpServiceHosts(this);
hostDiscover.start();
}
}
//
// public void setAuthAccount(String authAccount) {
// httpServiceHostsConfig.setAuthAccount(authAccount);
// }
//
//
//
// public void setAuthPassword(String authPassword) {
// httpServiceHostsConfig.setAuthPassword(authPassword);
// }
public void setHealth(String health) {
httpServiceHostsConfig.setHealth(health);
}
public void setDiscoverService(String discoverService) {
httpServiceHostsConfig.setDiscoverService(discoverService);
}
// public Map getAuthHeaders() {
// return authHeaders;
// }
public void toString(StringBuilder log){
httpServiceHostsConfig.toString(log,this.exceptionWare,this.hostDiscover);
}
public void setHosts(String hosts) {
httpServiceHostsConfig.setHosts(hosts);
}
public void addAddresses(List address){
this.serversList.addAddresses(address);
if(this.healthCheck != null){
this.healthCheck.checkNewAddresses(address);
}
for(HttpAddress host:address){
addressMap.put(host.getAddress(),host);
}
if(logger.isInfoEnabled()){
StringBuilder info = new StringBuilder();
info.append("Http pool[")
.append(getClientConfiguration().getBeanName()).append("]").append(" All live Http Servers:");
Iterator> iterator = this.addressMap.entrySet().iterator();
boolean firsted = true;
while(iterator.hasNext()){
Map.Entry esAddressEntry = iterator.next();
String host = esAddressEntry.getValue().getOriginAddress();
if(firsted){
info.append(host);
firsted = false;
}
else{
info.append(",").append(host);
}
}
logger.info(info.toString());
}
}
/**
* routing必须在配置文件中指定,否则中间不允许切换
* @param changed
* @param newCurrentRounte
*/
public void routingGroup(boolean changed, String newCurrentRounte){
if(this.routing == null || this.routing.equals("")){//routing必须在配置文件中指定,否则中间不允许切换
return;
}
if(!changed)
if(newCurrentRounte == null)
this.routingFilter = new RoutingFilter(this,this.addressList,routing);
else {
RoutingFilter routingFilter = new RoutingFilter(this, this.addressList, newCurrentRounte);
routingFilterWriteLock.lock();
try {
this.routing = newCurrentRounte;
this.routingFilter = routingFilter;
}
finally {
routingFilterWriteLock.unlock();
}
}
else{
RoutingFilter temp = new RoutingFilter(this,this.addressList,newCurrentRounte == null?routing:newCurrentRounte);
routingFilterWriteLock.lock();
try {
routingFilter = temp;
if(newCurrentRounte != null){
routing = newCurrentRounte;
}
}
finally {
routingFilterWriteLock.unlock();
}
}
}
public void handleRemoved(List hosts){
boolean hasHosts = true;
if(hosts == null || hosts.size() == 0){//没有可用节点
hasHosts = false;
}
Iterator> iterator = this.addressMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry esAddressEntry = iterator.next();
String host = esAddressEntry.getKey();
HttpAddress address = esAddressEntry.getValue();
if(hasHosts) {
boolean exist = false;
for (HttpHost httpHost : hosts) {
if (httpHost.getHostAddress().equals(host)) {
exist = true;
break;
}
}
if (!exist) {
address.setStatus(2);
if(logger.isInfoEnabled()){
logger.info(new StringBuilder().append("Http pool[")
.append(getClientConfiguration().getBeanName()).append("]").append(" Http Node[").append(address.toString()).append("] is down and removed.").toString());
}
}
}
else {
address.setStatus(2);
if(logger.isInfoEnabled()){
logger.info(new StringBuilder().append("Http pool[")
.append(getClientConfiguration().getBeanName()).append("]").append(" Http Node[").append(address.toString()).append("] is down and removed.").toString());
}
}
}
}
/**
* 如果有效更新了路由数据,则返回true
* @param address
* @param httpHost
* @return
*/
private boolean compareAndSetRouting(HttpAddress address,HttpHost httpHost){
String old = address.getRouting();
String routing = httpHost.getRouting();
address.setOriginAddress(httpHost.getOrigineAddress());
address.setRouting(routing);
if(old == null || old.equals("")){
return routing != null && !routing.equals("");
}
else{
if(routing == null || routing.equals(""))
return true;
else return !old.equals(routing);
}
}
/**
* 有没有有效处理节点数据
* @param hosts
* @return
*/
public boolean recoverRemovedNodes(List hosts) {
if(hosts == null || hosts.size() == 0){
return false;
}
boolean result = false;
for(HttpHost httpHost: hosts) {
HttpAddress address = this.addressMap.get(httpHost.getHostAddress());
if(address != null ){
address.setAttributes(httpHost.getAttributes());
if(!result)
result = compareAndSetRouting( address,httpHost);
else{
compareAndSetRouting( address,httpHost);
}
if(address.getStatus() == 2){//节点还原
address.onlySetStatus(0);
if(logger.isInfoEnabled()){
logger.info(new StringBuilder().append("Recover Removed Node [").append(address.toString()).append("] to Http pool[")
.append(getClientConfiguration().getBeanName()).append("] clusters addresses list.").toString());
}
}
}
}
return result;
}
public boolean containAddress(HttpAddress address){
return addressMap.containsKey(address.getAddress());
}
public void setHealthCheckInterval(long healthCheckInterval) {
httpServiceHostsConfig.setHealthCheckInterval( healthCheckInterval);
}
public long getDiscoverServiceInterval() {
return httpServiceHostsConfig.getDiscoverServiceInterval();
}
public void setDiscoverServiceInterval(long discoverServiceInterval){
httpServiceHostsConfig.setDiscoverServiceInterval( discoverServiceInterval);
}
public Boolean getHandleNullOrEmptyHostsByDiscovery() {
return httpServiceHostsConfig.getHandleNullOrEmptyHostsByDiscovery();
}
public void setHandleNullOrEmptyHostsByDiscovery(Boolean handleNullOrEmptyHostsByDiscovery) {
this.httpServiceHostsConfig.setHandleNullOrEmptyHostsByDiscovery(handleNullOrEmptyHostsByDiscovery);
}
public void setExceptionWare(String exceptionWare) {
httpServiceHostsConfig.setExceptionWare( exceptionWare);
}
public ExceptionWare getExceptionWare() {
return exceptionWare;
}
public void setExceptionWareBean(ExceptionWare exceptionWareBean) {
this.exceptionWare = exceptionWareBean;
}
public ClientConfiguration getClientConfiguration() {
return clientConfiguration;
}
public void setClientConfiguration(ClientConfiguration clientConfiguration) {
this.clientConfiguration = clientConfiguration;
}
public HttpHostDiscover getHostDiscover() {
return hostDiscover;
}
public void setHostDiscover(HttpHostDiscover hostDiscover) {
this.hostDiscover = hostDiscover;
}
public String getRouting() {
return routing;
}
private boolean hasRouting = false;
public void setRouting(String routing) {
this.routing = routing;
hasRouting = this.routing != null && !this.routing.equals("");
}
private boolean closed = false;
public synchronized void close() {
if(closed)
return;
closed = true;
if(hostDiscover != null) {
hostDiscover.stopCheck();
hostDiscover = null;
}
if(healthCheck != null) {
healthCheck.stopCheck();
healthCheck = null;
}
}
}