init
This commit is contained in:
		@@ -0,0 +1,50 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
			
		||||
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
    <parent>
 | 
			
		||||
        <artifactId>sentinel-transport</artifactId>
 | 
			
		||||
        <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
        <version>1.8.3</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
 | 
			
		||||
    <artifactId>sentinel-transport-spring-mvc</artifactId>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
        <apache.httpclient.version>4.5.3</apache.httpclient.version>
 | 
			
		||||
        <servlet.api.version>3.1.0</servlet.api.version>
 | 
			
		||||
        <spring.version>5.1.8.RELEASE</spring.version>
 | 
			
		||||
    </properties>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
            <artifactId>sentinel-transport-common</artifactId>
 | 
			
		||||
            <version>${project.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>junit</groupId>
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework</groupId>
 | 
			
		||||
            <artifactId>spring-webmvc</artifactId>
 | 
			
		||||
            <version>${spring.version}</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>javax.servlet</groupId>
 | 
			
		||||
            <artifactId>javax.servlet-api</artifactId>
 | 
			
		||||
            <version>${servlet.api.version}</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.apache.httpcomponents</groupId>
 | 
			
		||||
            <artifactId>httpclient</artifactId>
 | 
			
		||||
            <version>${apache.httpclient.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
</project>
 | 
			
		||||
@@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.command;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.command.CommandHandler;
 | 
			
		||||
import com.alibaba.csp.sentinel.command.CommandRequest;
 | 
			
		||||
import com.alibaba.csp.sentinel.command.CommandResponse;
 | 
			
		||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.command.http.StatusCode;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.log.CommandCenterLog;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.io.PrintWriter;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author shenbaoyong
 | 
			
		||||
 */
 | 
			
		||||
public class SentinelApiHandler {
 | 
			
		||||
 | 
			
		||||
    public static final String SERVER_ERROR_MESSAGE = "Command server error";
 | 
			
		||||
 | 
			
		||||
    private CommandHandler commandHandler;
 | 
			
		||||
 | 
			
		||||
    public SentinelApiHandler(CommandHandler commandHandler) {
 | 
			
		||||
        this.commandHandler = commandHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
 | 
			
		||||
        PrintWriter printWriter = null;
 | 
			
		||||
        try {
 | 
			
		||||
            long start = System.currentTimeMillis();
 | 
			
		||||
            printWriter = httpServletResponse.getWriter();
 | 
			
		||||
            CommandCenterLog.debug("[SentinelApiHandler] request income: {}", httpServletRequest.getRequestURL());
 | 
			
		||||
            CommandRequest request = new CommandRequest();
 | 
			
		||||
            Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
 | 
			
		||||
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
 | 
			
		||||
                String[] value = entry.getValue();
 | 
			
		||||
                if (value != null && value.length >= 1) {
 | 
			
		||||
                    request.addParam(entry.getKey(), value[0]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            CommandResponse<?> response = commandHandler.handle(request);
 | 
			
		||||
            handleResponse(response, httpServletResponse, printWriter);
 | 
			
		||||
 | 
			
		||||
            long cost = System.currentTimeMillis() - start;
 | 
			
		||||
            CommandCenterLog.debug("[SentinelApiHandler] Deal request: {}, time cost: {} ms", httpServletRequest.getRequestURL(), cost);
 | 
			
		||||
        } catch (Throwable e) {
 | 
			
		||||
            CommandCenterLog.warn("[SentinelApiHandler] error", e);
 | 
			
		||||
            try {
 | 
			
		||||
                if (printWriter != null) {
 | 
			
		||||
                    writeResponse(httpServletResponse, printWriter, StatusCode.INTERNAL_SERVER_ERROR, SERVER_ERROR_MESSAGE);
 | 
			
		||||
                }
 | 
			
		||||
            } catch (Exception e1) {
 | 
			
		||||
                CommandCenterLog.warn("Failed to write error response", e1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void writeResponse(HttpServletResponse httpServletResponse, PrintWriter out, StatusCode statusCode, String message) {
 | 
			
		||||
        httpServletResponse.setStatus(statusCode.getCode());
 | 
			
		||||
        if (message != null) {
 | 
			
		||||
            out.print(message);
 | 
			
		||||
        }
 | 
			
		||||
        out.flush();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private <T> void handleResponse(CommandResponse<T> response, HttpServletResponse httpServletResponse, final PrintWriter printWriter) throws Exception {
 | 
			
		||||
        if (response.isSuccess()) {
 | 
			
		||||
            if (response.getResult() == null) {
 | 
			
		||||
                writeResponse(httpServletResponse, printWriter, StatusCode.OK, null);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // Here we directly use `toString` to encode the result to plain text.
 | 
			
		||||
            byte[] buffer = response.getResult().toString().getBytes(SentinelConfig.charset());
 | 
			
		||||
            writeResponse(httpServletResponse, printWriter, StatusCode.OK, new String(buffer));
 | 
			
		||||
        } else {
 | 
			
		||||
            String msg = SERVER_ERROR_MESSAGE;
 | 
			
		||||
            if (response.getException() != null) {
 | 
			
		||||
                msg = response.getException().getMessage();
 | 
			
		||||
            }
 | 
			
		||||
            writeResponse(httpServletResponse, printWriter, StatusCode.BAD_REQUEST, msg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.command;
 | 
			
		||||
 | 
			
		||||
import org.springframework.core.Ordered;
 | 
			
		||||
import org.springframework.web.servlet.HandlerAdapter;
 | 
			
		||||
import org.springframework.web.servlet.ModelAndView;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author shenbaoyong
 | 
			
		||||
 */
 | 
			
		||||
public class SentinelApiHandlerAdapter implements HandlerAdapter, Ordered {
 | 
			
		||||
 | 
			
		||||
    private int order = Ordered.LOWEST_PRECEDENCE;
 | 
			
		||||
 | 
			
		||||
    public void setOrder(int order) {
 | 
			
		||||
        this.order = order;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getOrder() {
 | 
			
		||||
        return order;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean supports(Object handler) {
 | 
			
		||||
        return handler instanceof SentinelApiHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 | 
			
		||||
        SentinelApiHandler sentinelApiHandler = (SentinelApiHandler) handler;
 | 
			
		||||
        sentinelApiHandler.handle(request, response);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long getLastModified(HttpServletRequest request, Object handler) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,117 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.command;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.command.CommandHandler;
 | 
			
		||||
import com.alibaba.csp.sentinel.log.RecordLog;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.log.CommandCenterLog;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.StringUtil;
 | 
			
		||||
import org.springframework.beans.BeanWrapper;
 | 
			
		||||
import org.springframework.beans.BeanWrapperImpl;
 | 
			
		||||
import org.springframework.context.ApplicationEvent;
 | 
			
		||||
import org.springframework.context.ApplicationListener;
 | 
			
		||||
import org.springframework.core.Ordered;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
import org.springframework.web.servlet.HandlerExecutionChain;
 | 
			
		||||
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author shenbaoyong
 | 
			
		||||
 */
 | 
			
		||||
public class SentinelApiHandlerMapping extends AbstractHandlerMapping implements ApplicationListener {
 | 
			
		||||
 | 
			
		||||
    private static final String SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS = "org.springframework.boot.web.context.WebServerInitializedEvent";
 | 
			
		||||
    private static Class webServerInitializedEventClass;
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        try {
 | 
			
		||||
            webServerInitializedEventClass = ClassUtils.forName(SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS, null);
 | 
			
		||||
            RecordLog.info("[SentinelApiHandlerMapping] class {} is present, this is a spring-boot app, we can auto detect port", SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS);
 | 
			
		||||
        } catch (ClassNotFoundException e) {
 | 
			
		||||
            RecordLog.info("[SentinelApiHandlerMapping] class {} is not present, this is not a spring-boot app, we can not auto detect port", SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final static Map<String, CommandHandler> handlerMap = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
    private boolean ignoreInterceptor = true;
 | 
			
		||||
 | 
			
		||||
    public SentinelApiHandlerMapping() {
 | 
			
		||||
        setOrder(Ordered.LOWEST_PRECEDENCE - 10);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
 | 
			
		||||
        String commandName = request.getRequestURI();
 | 
			
		||||
        if (commandName.startsWith("/")) {
 | 
			
		||||
            commandName = commandName.substring(1);
 | 
			
		||||
        }
 | 
			
		||||
        CommandHandler commandHandler = handlerMap.get(commandName);
 | 
			
		||||
        return commandHandler != null ? new SentinelApiHandler(commandHandler) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
 | 
			
		||||
        return ignoreInterceptor ? new HandlerExecutionChain(handler) : super.getHandlerExecutionChain(handler, request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setIgnoreInterceptor(boolean ignoreInterceptor) {
 | 
			
		||||
        this.ignoreInterceptor = ignoreInterceptor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void registerCommand(String commandName, CommandHandler handler) {
 | 
			
		||||
        if (StringUtil.isEmpty(commandName) || handler == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (handlerMap.containsKey(commandName)) {
 | 
			
		||||
            CommandCenterLog.warn("[SentinelApiHandlerMapping] Register failed (duplicate command): " + commandName);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handlerMap.put(commandName, handler);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void registerCommands(Map<String, CommandHandler> handlerMap) {
 | 
			
		||||
        if (handlerMap != null) {
 | 
			
		||||
            for (Map.Entry<String, CommandHandler> e : handlerMap.entrySet()) {
 | 
			
		||||
                registerCommand(e.getKey(), e.getValue());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
 | 
			
		||||
        if (webServerInitializedEventClass != null && webServerInitializedEventClass.isAssignableFrom(applicationEvent.getClass())) {
 | 
			
		||||
            Integer port = null;
 | 
			
		||||
            try {
 | 
			
		||||
                BeanWrapper beanWrapper = new BeanWrapperImpl(applicationEvent);
 | 
			
		||||
                port = (Integer) beanWrapper.getPropertyValue("webServer.port");
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                RecordLog.warn("[SentinelApiHandlerMapping] resolve port from event " + applicationEvent + " fail", e);
 | 
			
		||||
            }
 | 
			
		||||
            if (port != null && TransportConfig.getPort() == null) {
 | 
			
		||||
                RecordLog.info("[SentinelApiHandlerMapping] resolve port {} from event {}", port, applicationEvent);
 | 
			
		||||
                TransportConfig.setRuntimePort(port);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.command;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.command.CommandHandler;
 | 
			
		||||
import com.alibaba.csp.sentinel.command.CommandHandlerProvider;
 | 
			
		||||
import com.alibaba.csp.sentinel.spi.Spi;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.CommandCenter;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author shenbaoyong
 | 
			
		||||
 */
 | 
			
		||||
@Spi(order = Spi.ORDER_LOWEST - 100)
 | 
			
		||||
public class SpringMvcHttpCommandCenter implements CommandCenter {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void start() throws Exception {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void stop() throws Exception {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void beforeStart() throws Exception {
 | 
			
		||||
        // Register handlers
 | 
			
		||||
        Map<String, CommandHandler> handlers = CommandHandlerProvider.getInstance().namedHandlers();
 | 
			
		||||
        SentinelApiHandlerMapping.registerCommands(handlers);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.command.http;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Jason Joo
 | 
			
		||||
 */
 | 
			
		||||
public enum StatusCode {
 | 
			
		||||
    /**
 | 
			
		||||
     * 200 OK.
 | 
			
		||||
     */
 | 
			
		||||
    OK(200, "OK"),
 | 
			
		||||
    BAD_REQUEST(400, "Bad Request"),
 | 
			
		||||
    REQUEST_TIMEOUT(408, "Request Timeout"),
 | 
			
		||||
    LENGTH_REQUIRED(411, "Length Required"),
 | 
			
		||||
    UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
 | 
			
		||||
    INTERNAL_SERVER_ERROR(500, "Internal Server Error");
 | 
			
		||||
    
 | 
			
		||||
    private int code;
 | 
			
		||||
    private String desc;
 | 
			
		||||
    private String representation;
 | 
			
		||||
    
 | 
			
		||||
    StatusCode(int code, String desc) {
 | 
			
		||||
        this.code = code;
 | 
			
		||||
        this.desc = desc;
 | 
			
		||||
        this.representation = code + " " + desc;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public int getCode() {
 | 
			
		||||
        return code;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public String getDesc() {
 | 
			
		||||
        return desc;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return representation;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,123 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.heartbeat;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.Constants;
 | 
			
		||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.log.RecordLog;
 | 
			
		||||
import com.alibaba.csp.sentinel.spi.Spi;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.endpoint.Endpoint;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.heartbeat.client.HttpClientsFactory;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.AppNameUtil;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.HostNameUtil;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.PidUtil;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.StringUtil;
 | 
			
		||||
import org.apache.http.client.config.RequestConfig;
 | 
			
		||||
import org.apache.http.client.methods.CloseableHttpResponse;
 | 
			
		||||
import org.apache.http.client.methods.HttpGet;
 | 
			
		||||
import org.apache.http.client.utils.URIBuilder;
 | 
			
		||||
import org.apache.http.impl.client.CloseableHttpClient;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 * @author Carpenter Lee
 | 
			
		||||
 * @author Leo Li
 | 
			
		||||
 */
 | 
			
		||||
@Spi(order = Spi.ORDER_LOWEST - 100)
 | 
			
		||||
public class SpringMvcHttpHeartbeatSender implements HeartbeatSender {
 | 
			
		||||
 | 
			
		||||
    private final CloseableHttpClient client;
 | 
			
		||||
 | 
			
		||||
    private static final int OK_STATUS = 200;
 | 
			
		||||
 | 
			
		||||
    private final int timeoutMs = 3000;
 | 
			
		||||
    private final RequestConfig requestConfig = RequestConfig.custom()
 | 
			
		||||
        .setConnectionRequestTimeout(timeoutMs)
 | 
			
		||||
        .setConnectTimeout(timeoutMs)
 | 
			
		||||
        .setSocketTimeout(timeoutMs)
 | 
			
		||||
        .build();
 | 
			
		||||
 | 
			
		||||
    private final Protocol consoleProtocol;
 | 
			
		||||
    private final String consoleHost;
 | 
			
		||||
    private final int consolePort;
 | 
			
		||||
 | 
			
		||||
    public SpringMvcHttpHeartbeatSender() {
 | 
			
		||||
        List<Endpoint> dashboardList = TransportConfig.getConsoleServerList();
 | 
			
		||||
        if (dashboardList == null || dashboardList.isEmpty()) {
 | 
			
		||||
            RecordLog.info("[HttpHeartbeatSender] No dashboard server available");
 | 
			
		||||
            consoleProtocol = Protocol.HTTP;
 | 
			
		||||
            consoleHost = null;
 | 
			
		||||
            consolePort = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            consoleProtocol = dashboardList.get(0).getProtocol();
 | 
			
		||||
            consoleHost = dashboardList.get(0).getHost();
 | 
			
		||||
            consolePort = dashboardList.get(0).getPort();
 | 
			
		||||
            RecordLog.info("[HttpHeartbeatSender] Dashboard address parsed: <{}:{}>", consoleHost, consolePort);
 | 
			
		||||
        }
 | 
			
		||||
        this.client = HttpClientsFactory.getHttpClientsByProtocol(consoleProtocol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean sendHeartbeat() throws Exception {
 | 
			
		||||
        if (StringUtil.isEmpty(consoleHost)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        URIBuilder uriBuilder = new URIBuilder();
 | 
			
		||||
        uriBuilder.setScheme(consoleProtocol.getProtocol()).setHost(consoleHost).setPort(consolePort)
 | 
			
		||||
            .setPath(TransportConfig.getHeartbeatApiPath())
 | 
			
		||||
            .setParameter("app", AppNameUtil.getAppName())
 | 
			
		||||
            .setParameter("app_type", String.valueOf(SentinelConfig.getAppType()))
 | 
			
		||||
            .setParameter("v", Constants.SENTINEL_VERSION)
 | 
			
		||||
            .setParameter("version", String.valueOf(System.currentTimeMillis()))
 | 
			
		||||
            .setParameter("hostname", HostNameUtil.getHostName())
 | 
			
		||||
            .setParameter("ip", TransportConfig.getHeartbeatClientIp())
 | 
			
		||||
            .setParameter("port", TransportConfig.getPort())
 | 
			
		||||
            .setParameter("pid", String.valueOf(PidUtil.getPid()));
 | 
			
		||||
 | 
			
		||||
        HttpGet request = new HttpGet(uriBuilder.build());
 | 
			
		||||
        request.setConfig(requestConfig);
 | 
			
		||||
        // Send heartbeat request.
 | 
			
		||||
        CloseableHttpResponse response = client.execute(request);
 | 
			
		||||
        response.close();
 | 
			
		||||
        int statusCode = response.getStatusLine().getStatusCode();
 | 
			
		||||
        if (statusCode == OK_STATUS) {
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (clientErrorCode(statusCode) || serverErrorCode(statusCode)) {
 | 
			
		||||
            RecordLog.warn("[HttpHeartbeatSender] Failed to send heartbeat to "
 | 
			
		||||
                + consoleHost + ":" + consolePort + ", http status code: " + statusCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long intervalMs() {
 | 
			
		||||
        return 5000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean clientErrorCode(int code) {
 | 
			
		||||
        return code > 399 && code < 500;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean serverErrorCode(int code) {
 | 
			
		||||
        return code > 499 && code < 600;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package com.alibaba.csp.sentinel.transport.heartbeat.client;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
 | 
			
		||||
import com.alibaba.csp.sentinel.transport.ssl.SslFactory;
 | 
			
		||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
 | 
			
		||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 | 
			
		||||
import org.apache.http.impl.client.CloseableHttpClient;
 | 
			
		||||
import org.apache.http.impl.client.HttpClients;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Leo Li
 | 
			
		||||
 */
 | 
			
		||||
public class HttpClientsFactory {
 | 
			
		||||
 | 
			
		||||
    private static class SslConnectionSocketFactoryInstance {
 | 
			
		||||
        private static final SSLConnectionSocketFactory SSL_CONNECTION_SOCKET_FACTORY = new SSLConnectionSocketFactory(SslFactory.getSslConnectionSocketFactory(), NoopHostnameVerifier.INSTANCE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CloseableHttpClient getHttpClientsByProtocol(Protocol protocol) {
 | 
			
		||||
        return protocol == Protocol.HTTP ? HttpClients.createDefault() : HttpClients.custom().
 | 
			
		||||
                setSSLSocketFactory(SslConnectionSocketFactoryInstance.SSL_CONNECTION_SOCKET_FACTORY).build();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.alibaba.csp.sentinel.transport.command.SpringMvcHttpCommandCenter
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.alibaba.csp.sentinel.transport.heartbeat.SpringMvcHttpHeartbeatSender
 | 
			
		||||
		Reference in New Issue
	
	Block a user