├── .gitignore ├── LICENSE ├── README.md ├── pom.xml ├── s2g-zuul-core ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── spring2go │ │ ├── tools │ │ ├── InfoBoard.java │ │ ├── common │ │ │ ├── AbstractHandler.java │ │ │ ├── ClassStats.java │ │ │ ├── GCStats.java │ │ │ ├── LogHandler.java │ │ │ ├── MemoryStats.java │ │ │ ├── OperatingSystemStats.java │ │ │ ├── Stats.java │ │ │ ├── StatsGetter.java │ │ │ ├── StatsHandler.java │ │ │ ├── StatusInfo.java │ │ │ └── ThreadStats.java │ │ ├── servlet │ │ │ ├── EnvServlet.java │ │ │ ├── HystrixServlet.java │ │ │ ├── PropsServlet.java │ │ │ ├── StaticServlet.java │ │ │ └── StatusServlet.java │ │ ├── stat │ │ │ ├── ClassStatsGetter.java │ │ │ ├── GCStatsGetter.java │ │ │ ├── JvmStatsReporter.java │ │ │ ├── MemoryStatsGetter.java │ │ │ ├── OperatingSystemStatsGetter.java │ │ │ └── ThreadStatsGetter.java │ │ └── util │ │ │ ├── ByteUtil.java │ │ │ └── TimeUtil.java │ │ └── zuul │ │ ├── common │ │ ├── CatContext.java │ │ ├── Constants.java │ │ ├── ExecutionStatus.java │ │ ├── FilterInfo.java │ │ ├── HttpServletRequestWrapper.java │ │ ├── HttpServletResponseWrapper.java │ │ ├── IDynamicCodeCompiler.java │ │ ├── IFilterFactory.java │ │ ├── IFilterUsageNotifier.java │ │ ├── IMonitor.java │ │ ├── INamedCount.java │ │ ├── ITracer.java │ │ ├── IZuulFilter.java │ │ ├── IZuulFilterDao.java │ │ ├── IZuulFilterDaoBuilder.java │ │ ├── ServletInputStreamWrapper.java │ │ ├── ZuulException.java │ │ ├── ZuulFilterResult.java │ │ └── ZuulHeaders.java │ │ ├── context │ │ └── RequestContext.java │ │ ├── core │ │ ├── FilterFileManager.java │ │ ├── FilterLoader.java │ │ ├── FilterProcessor.java │ │ ├── LogConfigurator.java │ │ ├── ZuulCallable.java │ │ └── ZuulRunner.java │ │ ├── filters │ │ ├── DefaultFilterFactory.java │ │ ├── FilterRegistry.java │ │ ├── FilterScriptManagerServlet.java │ │ ├── FilterVerifier.java │ │ ├── HttpZuulFilterDao.java │ │ ├── HttpZuulFilterDaoBuilder.java │ │ ├── HystrixZuulFilterDao.java │ │ ├── JDBCZuulFilterDao.java │ │ ├── JDBCZuulFilterDaoBuilder.java │ │ ├── ZuulFilter.java │ │ ├── ZuulFilterDaoFactory.java │ │ └── ZuulFilterPoller.java │ │ ├── groovy │ │ ├── GroovyCompiler.java │ │ └── GroovyFileFilter.java │ │ ├── hystrix │ │ ├── DiscoveryServerList.java │ │ ├── HttpClientResponse.java │ │ ├── RestClient.java │ │ ├── RestClientFactory.java │ │ ├── RibbonRequestCommandForSemaphoreIsolation.java │ │ ├── RibbonRequestCommandForThreadIsolation.java │ │ ├── RibbonZuulCommon.java │ │ ├── ZuulCommandHelper.java │ │ ├── ZuulRequestCommandForSemaphoreIsolation.java │ │ └── ZuulRequestCommandForThreadIsolation.java │ │ ├── mobile │ │ ├── DebugHeader.java │ │ ├── DebugModeSetter.java │ │ ├── DebugRequest.java │ │ ├── DebugResponse.java │ │ ├── ErrorResponse.java │ │ ├── HealthCheck.java │ │ ├── MobileAddTimeStamp.java │ │ ├── MobileExecuteRoute.java │ │ ├── SendResponse.java │ │ ├── Stats.java │ │ └── TestRouting.java │ │ ├── monitoring │ │ ├── Counter.java │ │ ├── CounterFactory.java │ │ ├── ErrorStatsData.java │ │ ├── ErrorStatsManager.java │ │ ├── MetricPoller.java │ │ ├── MonitorRegistry.java │ │ ├── NamedCountingMonitor.java │ │ ├── RouteErrorMonitor.java │ │ ├── RouteStatusCodeMonitor.java │ │ ├── ServoMonitor.java │ │ ├── StatManager.java │ │ ├── Tracer.java │ │ └── TracerFactory.java │ │ ├── servlet │ │ └── CatServletFilter.java │ │ └── util │ │ ├── AdminFilterUtil.java │ │ ├── Debug.java │ │ ├── DeepCopy.java │ │ ├── HTTPRequestUtil.java │ │ ├── HttpUtil.java │ │ ├── IPUtil.java │ │ ├── JSONUtils.java │ │ ├── MonitoringUtil.java │ │ ├── S2gUtil.java │ │ ├── SleepUtil.java │ │ └── StringUtil.java │ └── resources │ └── content │ ├── index.html │ └── jquery-2.1.1.min.js └── s2g-zuul-mobile ├── pom.xml └── src ├── main ├── java │ └── io │ │ └── spring2go │ │ └── zuul │ │ └── servlet │ │ ├── AsyncZuulListener.java │ │ ├── AsyncZuulServlet.java │ │ ├── InitializeServletListener.java │ │ └── SyncZuulServlet.java ├── resources │ ├── .gitignore │ ├── META-INF │ │ └── app.properties │ ├── db │ │ └── schema.sql │ ├── mobile_zuul-logback-prod.xml │ ├── mobile_zuul-logback-test.xml │ ├── mobile_zuul-logback-uat.xml │ ├── mobile_zuul-logback.xml │ ├── mobile_zuul-prod.properties │ ├── mobile_zuul-test.properties │ ├── mobile_zuul-uat.properties │ └── mobile_zuul.properties └── webapp │ ├── WEB-INF │ └── web.xml │ └── admin │ └── filterLoader.jsp └── scripts ├── error └── ErrorResponse.groovy ├── post ├── AddTimeStamp.groovy ├── DebugHeader.groovy ├── DebugResponse.groovy ├── SendResponse.groovy └── Stats.groovy ├── pre ├── DebugModeSetter.groovy ├── DebugRequest.groovy ├── HealthCheck.groovy └── TestRoute.groovy └── route ├── ExecuteRibbon.groovy └── ExecuteRoute.groovy /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | *.iml 19 | .gradle 20 | local.properties 21 | .idea/workspace.xml 22 | .idea/libraries 23 | .DS_Store 24 | build/ 25 | captures/ 26 | .externalNativeBuild 27 | 28 | ### NetBeans ### 29 | nbproject/private/ 30 | build/ 31 | nbbuild/ 32 | dist/ 33 | nbdist/ 34 | .nb-gradle/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 spring2go.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # s2g-zuul 2 | Spring2go定制版Netflix zuul 3 | 4 | ## 注意!!! 5 | 6 | 1. 本项目为微服务课程讲解开发,代码仅供学习参考,如需生产化,需要做生产化扩展+严格测试!!!另外请考虑Spring Cloud Zuul。 7 | 2. 注意本项目依赖[CAT3.0](https://github.com/dianping/cat)客户端,启动前需要先CAT客户端配置工作,否则Servlet会启不来,步骤如下描述。 8 | 9 | ## 建议 10 | 11 | s2g-zuul源码建议使用较新版本的[Eclipse IDE for Java EE Developer](https://www.eclipse.org/downloads/packages/release/2019-03/r/eclipse-ide-enterprise-java-developers 12 | )进行导入,它可以自动感知Servlet Web项目,可在Eclipse+Tomcat里头直接调试源码,方便排查问题。 13 | 14 | ## 启动 cat 客户端前的准备工作 15 | 16 | 1. 创建 `/data/appdatas/cat` 目录 17 | 18 | 确保你具有这个目录的读写权限。 19 | 20 | 2. 创建 `/data/applogs/cat` 目录 (可选) 21 | 22 | 这个目录是用于存放运行时日志的,这将会对调试提供很大帮助,同样需要读写权限。 23 | 24 | 3. 创建 `/data/appdatas/cat/client.xml`,内容如下 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | > 如果不实际使用CAT,只是验证Zuul功能,则上面CAT服务器地址可以随意填;如果要实际启用CAT服务器,则上面需要填写你的CAT server地址。 36 | 37 | 注意,上述目录和zuul在要在同一逻辑盘下。 38 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/InfoBoard.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools; 2 | 3 | import org.eclipse.jetty.server.Server; 4 | import org.eclipse.jetty.server.session.SessionHandler; 5 | import org.eclipse.jetty.servlet.ServletContextHandler; 6 | import org.eclipse.jetty.servlet.ServletHolder; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet; 11 | 12 | import io.spring2go.tools.common.StatusInfo; 13 | import io.spring2go.tools.servlet.EnvServlet; 14 | import io.spring2go.tools.servlet.HystrixServlet; 15 | import io.spring2go.tools.servlet.PropsServlet; 16 | import io.spring2go.tools.servlet.StaticServlet; 17 | import io.spring2go.tools.servlet.StatusServlet; 18 | import io.spring2go.tools.stat.JvmStatsReporter; 19 | 20 | public class InfoBoard { 21 | private Logger logger = LoggerFactory.getLogger(InfoBoard.class); 22 | 23 | private String appName; 24 | private Server server; 25 | 26 | private volatile boolean running = false; 27 | 28 | private StatusInfo statusInfo; 29 | private JvmStatsReporter jvmStatsReporter; 30 | 31 | public InfoBoard(String appName, int port) { 32 | this.appName = appName; 33 | this.server = new Server(port); 34 | this.statusInfo = new StatusInfo(); 35 | this.jvmStatsReporter = new JvmStatsReporter(appName, 60000); 36 | this.jvmStatsReporter.addStatsHandler(statusInfo); 37 | this.jvmStatsReporter.start(); 38 | try { 39 | ServletContextHandler handler = new ServletContextHandler(); 40 | handler.setContextPath("/"); 41 | 42 | handler.setSessionHandler(new SessionHandler()); 43 | 44 | handler.addServlet(EnvServlet.class, "/api/env"); 45 | handler.addServlet(PropsServlet.class, "/api/props"); 46 | handler.addServlet(StaticServlet.class, "/*"); 47 | handler.addServlet(HystrixServlet.class, "/breaker"); 48 | handler.addServlet(HystrixMetricsStreamServlet.class, "/hystrix.stream"); 49 | handler.addServlet(new ServletHolder(new StatusServlet(statusInfo)), "/api/status"); 50 | 51 | server.setHandler(handler); 52 | 53 | } catch (Exception e) { 54 | logger.error("start jetty error!", e); 55 | } 56 | 57 | } 58 | 59 | public synchronized void start() { 60 | if (!running) { 61 | try { 62 | server.start(); 63 | running = true; 64 | } catch (Exception e) { 65 | logger.error("Exception in Starting " + this.getClass().getSimpleName(), e); 66 | } 67 | } 68 | } 69 | 70 | public synchronized void shutdown() { 71 | if (running) { 72 | try { 73 | server.stop(); 74 | running = false; 75 | } catch (Exception e) { 76 | logger.error("Exception in Stopping " + this.getClass().getSimpleName(), e); 77 | if (!server.isStarted() && !server.isStarting()) 78 | running = false; 79 | } 80 | } 81 | } 82 | 83 | public boolean isRunning() { 84 | return running; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/AbstractHandler.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | 4 | 5 | public abstract class AbstractHandler implements StatsHandler { 6 | @Override 7 | public void process(Stats stats) { 8 | if(stats == null) return; 9 | 10 | if(stats instanceof ClassStats) processClassStats((ClassStats) stats); 11 | else if(stats instanceof ThreadStats) processThreadStats((ThreadStats) stats); 12 | else if(stats instanceof MemoryStats) processMemoryStats((MemoryStats) stats); 13 | else if(stats instanceof GCStats) processGCStats((GCStats) stats); 14 | else if(stats instanceof OperatingSystemStats) processOperatingSystemStats((OperatingSystemStats) stats); 15 | } 16 | 17 | protected abstract void processGCStats(GCStats stats); 18 | 19 | protected abstract void processMemoryStats(MemoryStats stats); 20 | 21 | protected abstract void processThreadStats(ThreadStats stats); 22 | 23 | protected abstract void processClassStats(ClassStats stats); 24 | 25 | protected abstract void processOperatingSystemStats(OperatingSystemStats stats); 26 | } 27 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/ClassStats.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | 4 | 5 | public class ClassStats implements Stats { 6 | 7 | private int currentClassCount; 8 | private long beenLoadedClassCount; 9 | private long beenUnloadedClassCount; 10 | 11 | public int getCurrentClassCount() { 12 | return currentClassCount; 13 | } 14 | 15 | public void setCurrentClassCount(int currentClassCount) { 16 | this.currentClassCount = currentClassCount; 17 | } 18 | 19 | public long getBeenLoadedClassCount() { 20 | return beenLoadedClassCount; 21 | } 22 | 23 | public void setBeenLoadedClassCount(long beenLoadedClassCount) { 24 | this.beenLoadedClassCount = beenLoadedClassCount; 25 | } 26 | 27 | public long getBeenUnloadedClassCount() { 28 | return beenUnloadedClassCount; 29 | } 30 | 31 | public void setBeenUnloadedClassCount(long beenUnloadedClassCount) { 32 | this.beenUnloadedClassCount = beenUnloadedClassCount; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "\nClassStats{" + 38 | "\n\tcurrentClassCount=" + currentClassCount + 39 | ", \n\tbeenLoadedClassCount=" + beenLoadedClassCount + 40 | ", \n\tbeenUnloadedClassCount=" + beenUnloadedClassCount + 41 | "\n}"; 42 | } 43 | 44 | @Override 45 | public String toJsonStr() { 46 | return "{" + 47 | "\"currentClassCount\":\"" + currentClassCount + 48 | "\", \"beenLoadedClassCount\":\"" + beenLoadedClassCount + 49 | "\", \"beenUnloadedClassCount\":\"" + beenUnloadedClassCount + 50 | "\"}"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/GCStats.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | 4 | public class GCStats implements Stats { 5 | private long minorGcCount; 6 | private long minorGcTime; 7 | 8 | private long fullGcCount; 9 | private long fullGcTime; 10 | 11 | private long otherGcCount; 12 | private long otherGcTime; 13 | 14 | 15 | public long getMinorGcCount() { 16 | return minorGcCount; 17 | } 18 | 19 | public void setMinorGcCount(long minorGcCount) { 20 | this.minorGcCount = minorGcCount; 21 | } 22 | 23 | public long getMinorGcTime() { 24 | return minorGcTime; 25 | } 26 | 27 | public void setMinorGcTime(long minorGcTime) { 28 | this.minorGcTime = minorGcTime; 29 | } 30 | 31 | public long getFullGcCount() { 32 | return fullGcCount; 33 | } 34 | 35 | public void setFullGcCount(long fullGcCount) { 36 | this.fullGcCount = fullGcCount; 37 | } 38 | 39 | public long getFullGcTime() { 40 | return fullGcTime; 41 | } 42 | 43 | public void setFullGcTime(long fullGcTime) { 44 | this.fullGcTime = fullGcTime; 45 | } 46 | 47 | public long getOtherGcCount() { 48 | return otherGcCount; 49 | } 50 | 51 | public void setOtherGcCount(long otherGcCount) { 52 | this.otherGcCount = otherGcCount; 53 | } 54 | 55 | public long getOtherGcTime() { 56 | return otherGcTime; 57 | } 58 | 59 | public void setOtherGcTime(long otherGcTime) { 60 | this.otherGcTime = otherGcTime; 61 | } 62 | 63 | @Override 64 | public String toJsonStr() { 65 | return "{" + 66 | "\"minorGcCount\":\"" + minorGcCount + 67 | "\", \"minorGcTimeMS\":\"" + minorGcTime + 68 | "\", \"fullGcCount\":\"" + fullGcCount + 69 | "\", \"fullGcTimeMS\":\"" + fullGcTime + 70 | "\", \"otherGcCount\":\"" + otherGcCount + 71 | "\", \"otherGcTime\":\"" + otherGcTime + 72 | "\"}"; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return "\nGCStats{" + 78 | "\n\tminorGcCount=" + minorGcCount + 79 | ",\n\tminorGcTime=" + minorGcTime + 80 | ",\n\tfullGcCount=" + fullGcCount + 81 | ",\n\tfullGcTime=" + fullGcTime + 82 | ",\n\totherGcCount=" + otherGcCount + 83 | ",\n\totherGcTime=" + otherGcTime + 84 | "\n}"; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/LogHandler.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | 7 | public class LogHandler implements StatsHandler { 8 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 9 | 10 | @Override 11 | public void process(Stats stats) { 12 | logger.info(stats.toString()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/MemoryStats.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | import io.spring2go.tools.util.ByteUtil; 4 | 5 | public class MemoryStats implements Stats { 6 | private long heapUsedMemory; 7 | private long heapCommitedMemory; 8 | private long heapMaxMemory; 9 | 10 | private long nonHeapUsedMemory; 11 | private long nonHeapCommitedMemory; 12 | private long nonHeapMaxMemory; 13 | 14 | public long getHeapUsedMemory() { 15 | return heapUsedMemory; 16 | } 17 | 18 | public void setHeapUsedMemory(long heapUsedMemory) { 19 | this.heapUsedMemory = heapUsedMemory; 20 | } 21 | 22 | public long getHeapCommitedMemory() { 23 | return heapCommitedMemory; 24 | } 25 | 26 | public void setHeapCommitedMemory(long heapCommitedMemory) { 27 | this.heapCommitedMemory = heapCommitedMemory; 28 | } 29 | 30 | public long getHeapMaxMemory() { 31 | return heapMaxMemory; 32 | } 33 | 34 | public void setHeapMaxMemory(long heapMaxMemory) { 35 | this.heapMaxMemory = heapMaxMemory; 36 | } 37 | 38 | public long getNonHeapUsedMemory() { 39 | return nonHeapUsedMemory; 40 | } 41 | 42 | public void setNonHeapUsedMemory(long nonHeapUsedMemory) { 43 | this.nonHeapUsedMemory = nonHeapUsedMemory; 44 | } 45 | 46 | public long getNonHeapCommitedMemory() { 47 | return nonHeapCommitedMemory; 48 | } 49 | 50 | public void setNonHeapCommitedMemory(long nonHeapCommitedMemory) { 51 | this.nonHeapCommitedMemory = nonHeapCommitedMemory; 52 | } 53 | 54 | public long getNonHeapMaxMemory() { 55 | return nonHeapMaxMemory; 56 | } 57 | 58 | public void setNonHeapMaxMemory(long nonHeapMaxMemory) { 59 | this.nonHeapMaxMemory = nonHeapMaxMemory; 60 | } 61 | 62 | @Override 63 | public String toJsonStr() { 64 | return "{" + 65 | "\"heapUsedMemory\":\"" + ByteUtil.bytesToSize(heapUsedMemory) + 66 | "\", \"heapCommitedMemory\":\"" + ByteUtil.bytesToSize(heapCommitedMemory) + 67 | "\", \"heapMaxMemory\":\"" + ByteUtil.bytesToSize(heapMaxMemory) + 68 | "\", \"nonHeapUsedMemory\":\"" + ByteUtil.bytesToSize(nonHeapUsedMemory) + 69 | "\", \"nonHeapCommitedMemory\":\"" + ByteUtil.bytesToSize(nonHeapCommitedMemory) + 70 | "\", \"nonHeapMaxMemory\":\"" + ByteUtil.bytesToSize(nonHeapMaxMemory) + 71 | "\"}"; 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | return "\nMemoryStats{" + 77 | "\n\theapUsedMemory=" + ByteUtil.bytesToSize(heapUsedMemory) + 78 | ", \n\theapCommitedMemory=" + ByteUtil.bytesToSize(heapCommitedMemory) + 79 | ", \n\theapMaxMemory=" + ByteUtil.bytesToSize(heapMaxMemory) + 80 | ", \n\tnonHeapUsedMemory=" + ByteUtil.bytesToSize(nonHeapUsedMemory) + 81 | ", \n\tnonHeapCommitedMemory=" + ByteUtil.bytesToSize(nonHeapCommitedMemory) + 82 | ", \n\tnonHeapMaxMemory=" + ByteUtil.bytesToSize(nonHeapMaxMemory) + 83 | "\n}"; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/Stats.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | 4 | public interface Stats { 5 | String toJsonStr(); 6 | } 7 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/StatsGetter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | 4 | public interface StatsGetter { 5 | 6 | Stats get(); 7 | } 8 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/StatsHandler.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | 4 | public interface StatsHandler { 5 | void process(Stats stats); 6 | } 7 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/StatusInfo.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | public class StatusInfo extends AbstractHandler{ 4 | volatile GCStats gcStats = new GCStats(); 5 | volatile MemoryStats memoryStats = new MemoryStats(); 6 | volatile ThreadStats threadStats = new ThreadStats(); 7 | volatile ClassStats classStats = new ClassStats(); 8 | volatile OperatingSystemStats systemStats = new OperatingSystemStats(); 9 | 10 | public GCStats getGCStats(){ 11 | return this.gcStats; 12 | } 13 | 14 | @Override 15 | protected void processGCStats(GCStats gcStats) { 16 | this.gcStats = gcStats; 17 | } 18 | 19 | @Override 20 | protected void processMemoryStats(MemoryStats memoryStats) { 21 | this.memoryStats = memoryStats; 22 | } 23 | 24 | @Override 25 | protected void processThreadStats(ThreadStats threadStats) { 26 | this.threadStats = threadStats; 27 | } 28 | 29 | @Override 30 | protected void processClassStats(ClassStats classStats) { 31 | this.classStats = classStats; 32 | } 33 | 34 | @Override 35 | protected void processOperatingSystemStats(OperatingSystemStats operatingSystemStats) { 36 | this.systemStats = operatingSystemStats; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/common/ThreadStats.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.common; 2 | 3 | public class ThreadStats implements Stats { 4 | //Include daemon and none-daemon 5 | private int currentThreadCount; 6 | 7 | private int daemonThreadCount; 8 | 9 | private long beenCreatedThreadCount; 10 | 11 | public int getCurrentThreadCount() { 12 | return currentThreadCount; 13 | } 14 | 15 | public void setCurrentThreadCount(int currentThreadCount) { 16 | this.currentThreadCount = currentThreadCount; 17 | } 18 | 19 | public int getDaemonThreadCount() { 20 | return daemonThreadCount; 21 | } 22 | 23 | public void setDaemonThreadCount(int daemonThreadCount) { 24 | this.daemonThreadCount = daemonThreadCount; 25 | } 26 | 27 | public long getBeenCreatedThreadCount() { 28 | return beenCreatedThreadCount; 29 | } 30 | 31 | public void setBeenCreatedThreadCount(long beenCreatedThreadCount) { 32 | this.beenCreatedThreadCount = beenCreatedThreadCount; 33 | } 34 | 35 | @Override 36 | public String toJsonStr() { 37 | return "{" + 38 | "\"currentThreadCount\":\"" + currentThreadCount + 39 | "\", \"daemonThreadCount\":\"" + daemonThreadCount + 40 | "\", \"beenCreatedThreadCount\":\"" + beenCreatedThreadCount + 41 | "\"}"; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "\nThreadStats{" + 47 | "\t\ncurrentThreadCount=" + currentThreadCount + 48 | ", \t\ndaemonThreadCount=" + daemonThreadCount + 49 | ", \t\nbeenCreatedThreadCount=" + beenCreatedThreadCount + 50 | "\n}"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/servlet/EnvServlet.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.servlet; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.util.Map; 6 | import java.util.TreeMap; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | import org.eclipse.jetty.server.Response; 14 | 15 | import com.alibaba.fastjson.JSON; 16 | 17 | public class EnvServlet extends HttpServlet{ 18 | 19 | @Override 20 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 21 | 22 | // make a writable copy of the immutable System.getenv() map 23 | Map envVarsMap = new TreeMap(System.getenv()); 24 | 25 | String jsonStr = JSON.toJSONString(envVarsMap); 26 | 27 | resp.addHeader("Access-Control-Allow-Origin", "*"); 28 | resp.addHeader("Access-Control-Allow-Headers","Content-Type, Accept"); 29 | resp.setContentType("application/json; charset=UTF-8"); 30 | 31 | PrintWriter writer = resp.getWriter(); 32 | try{ 33 | writer.write(jsonStr); 34 | resp.setStatus(Response.SC_OK); 35 | } finally { 36 | if (writer != null) { 37 | writer.close(); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/servlet/HystrixServlet.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.servlet; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.util.Map; 6 | import java.util.TreeMap; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | import org.eclipse.jetty.server.Response; 14 | 15 | import com.alibaba.fastjson.JSON; 16 | import com.netflix.config.DynamicPropertyFactory; 17 | import com.netflix.hystrix.HystrixCircuitBreaker; 18 | import com.netflix.hystrix.HystrixCommandKey; 19 | import com.netflix.hystrix.HystrixCommandMetrics; 20 | 21 | public class HystrixServlet extends HttpServlet { 22 | 23 | @Override 24 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 25 | PrintWriter writer = resp.getWriter(); 26 | try { 27 | 28 | // make a writable copy of the immutable System.getenv() map 29 | Map breakerMap = new TreeMap(); 30 | 31 | for (HystrixCommandMetrics commandMetrics : HystrixCommandMetrics.getInstances()) { 32 | HystrixCommandKey key = commandMetrics.getCommandKey(); 33 | HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key); 34 | 35 | if (circuitBreaker != null) { 36 | if (circuitBreaker.isOpen()) { 37 | breakerMap.put(key.name(), DynamicPropertyFactory.getInstance().getStringProperty("mail."+key.name(), "bobo@spring2go.com").get()); 38 | }else{ 39 | if(DynamicPropertyFactory.getInstance().getBooleanProperty("hystrix.command."+key.name()+".circuitBreaker.forceOpen",false).get()){ 40 | breakerMap.put(key.name(), DynamicPropertyFactory.getInstance().getStringProperty("mail."+key.name(), "bobo@spring2go.com").get()); 41 | }else if(DynamicPropertyFactory.getInstance().getBooleanProperty("hystrix.command.default.circuitBreaker.forceOpen",false).get()){ 42 | breakerMap.put(key.name(), DynamicPropertyFactory.getInstance().getStringProperty("mail."+key.name(), "bobo@spring2go.com").get()); 43 | } 44 | } 45 | } 46 | } 47 | 48 | String jsonStr = JSON.toJSONString(breakerMap); 49 | 50 | resp.addHeader("Access-Control-Allow-Origin", "*"); 51 | resp.addHeader("Access-Control-Allow-Headers", "Content-Type, Accept"); 52 | resp.setContentType("application/json; charset=UTF-8"); 53 | 54 | writer.write(jsonStr); 55 | resp.setStatus(Response.SC_OK); 56 | }catch(Throwable t){ 57 | writer.write(t.getMessage()); 58 | resp.setStatus(Response.SC_INTERNAL_SERVER_ERROR); 59 | }finally { 60 | 61 | if (writer != null) { 62 | writer.close(); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/servlet/PropsServlet.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.servlet; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | import org.apache.commons.configuration.AbstractConfiguration; 15 | import org.codehaus.jackson.map.ObjectMapper; 16 | import org.eclipse.jetty.server.Response; 17 | 18 | import com.alibaba.fastjson.JSON; 19 | import com.netflix.config.ConfigurationManager; 20 | 21 | public class PropsServlet extends HttpServlet { 22 | 23 | private ObjectMapper mapper = new ObjectMapper(); 24 | 25 | @Override 26 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 27 | Map allPropsAsString = new TreeMap(); 28 | AbstractConfiguration config = ConfigurationManager.getConfigInstance(); 29 | Iterator keys = config.getKeys(); 30 | 31 | while (keys.hasNext()) { 32 | final String key = keys.next(); 33 | final Object value; 34 | value = config.getProperty(key); 35 | allPropsAsString.put(key, value.toString()); 36 | } 37 | 38 | String jsonStr = JSON.toJSONString(allPropsAsString); 39 | //mapper.writeValueAsString(allPropsAsString); 40 | 41 | resp.addHeader("Access-Control-Allow-Origin", "*"); 42 | resp.addHeader("Access-Control-Allow-Headers","Content-Type, Accept"); 43 | resp.setContentType("application/json; charset=UTF-8"); 44 | 45 | PrintWriter writer = resp.getWriter(); 46 | try{ 47 | writer.write(jsonStr); 48 | resp.setStatus(Response.SC_OK); 49 | } finally { 50 | if (writer != null) { 51 | writer.close(); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/servlet/StaticServlet.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.servlet; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | 15 | import org.eclipse.jetty.server.Response; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | public class StaticServlet extends HttpServlet { 20 | 21 | final static Map EXT_TO_MEDIATYPE = new HashMap(); 22 | static { 23 | EXT_TO_MEDIATYPE.put("js", "text/javascript"); 24 | EXT_TO_MEDIATYPE.put("png", "image/png"); 25 | EXT_TO_MEDIATYPE.put("gif", "image/gif"); 26 | EXT_TO_MEDIATYPE.put("css", "text/css"); 27 | EXT_TO_MEDIATYPE.put("jpg", "image/jpeg"); 28 | EXT_TO_MEDIATYPE.put("jpeg", "image/jpeg"); 29 | EXT_TO_MEDIATYPE.put("html", "text/html"); 30 | } 31 | 32 | final static ConcurrentHashMap CONTENT_CACHE = new ConcurrentHashMap(); 33 | 34 | Logger logger = LoggerFactory.getLogger(this.getClass()); 35 | 36 | @Override 37 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 38 | String path = req.getRequestURI(); 39 | if(path.equals("/")){ 40 | path = "/index.html"; 41 | } 42 | String ext = path.substring(path.lastIndexOf(".")+1); 43 | String mediaType = EXT_TO_MEDIATYPE.get(ext); 44 | byte[] contentBytes = null; 45 | 46 | if(mediaType!=null){ 47 | contentBytes = CONTENT_CACHE.get(path); 48 | if (contentBytes == null) { 49 | InputStream is = getClass().getClassLoader().getResourceAsStream("content" + path); 50 | if (is != null) { 51 | try { 52 | ByteArrayOutputStream os = new ByteArrayOutputStream(4096); 53 | byte[] bs = new byte[4096]; 54 | int c = 0; 55 | while((c = is.read(bs)) > 0){ 56 | os.write(bs,0,c); 57 | } 58 | contentBytes=os.toByteArray(); 59 | CONTENT_CACHE.putIfAbsent(path, contentBytes); 60 | } catch (IOException e) { 61 | try { 62 | is.close(); 63 | } catch (IOException e1) { 64 | logger.warn("Could not close the resource " + path, e1); 65 | } 66 | } 67 | } 68 | 69 | } 70 | } 71 | 72 | if (contentBytes == null) { 73 | resp.sendError(Response.SC_NOT_FOUND); 74 | }else { 75 | 76 | resp.addHeader("Access-Control-Allow-Origin", "*"); 77 | resp.addHeader("Access-Control-Allow-Headers","Content-Type, Accept"); 78 | resp.setContentType(mediaType); 79 | resp.setStatus(Response.SC_OK); 80 | resp.getOutputStream().write(contentBytes); 81 | resp.getOutputStream().close(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/servlet/StatusServlet.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.servlet; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.lang.management.ManagementFactory; 6 | import java.lang.management.RuntimeMXBean; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | import javax.servlet.ServletException; 13 | import javax.servlet.http.HttpServlet; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | 17 | import org.eclipse.jetty.server.Response; 18 | 19 | import com.alibaba.fastjson.JSON; 20 | 21 | import io.spring2go.tools.common.StatusInfo; 22 | import io.spring2go.tools.stat.ClassStatsGetter; 23 | import io.spring2go.tools.stat.MemoryStatsGetter; 24 | import io.spring2go.tools.stat.OperatingSystemStatsGetter; 25 | import io.spring2go.tools.stat.ThreadStatsGetter; 26 | import io.spring2go.tools.util.TimeUtil; 27 | 28 | public class StatusServlet extends HttpServlet { 29 | 30 | private StatusInfo statusInfo; 31 | 32 | private ClassStatsGetter classStatsGetter; 33 | private ThreadStatsGetter threadStatsGetter; 34 | private MemoryStatsGetter memoryStatsGetter; 35 | private OperatingSystemStatsGetter operatingSystemStatsGetter; 36 | 37 | RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); 38 | 39 | public StatusServlet(StatusInfo statusInfo) { 40 | this.statusInfo = statusInfo; 41 | this.classStatsGetter = new ClassStatsGetter(); 42 | this.threadStatsGetter = new ThreadStatsGetter(); 43 | this.memoryStatsGetter = new MemoryStatsGetter(); 44 | this.operatingSystemStatsGetter = new OperatingSystemStatsGetter(); 45 | } 46 | 47 | @Override 48 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 49 | 50 | Map props = new LinkedHashMap(); 51 | 52 | props.put("Server Start Time", new SimpleDateFormat("yyyy-MM-dd HH:ss").format(new Date(rb.getStartTime()))); 53 | props.put("Server Up Time", TimeUtil.readableTimeInterval(rb.getUptime())); 54 | 55 | addJsonContent(props, "System ", operatingSystemStatsGetter.get().toJsonStr()); 56 | addJsonContent(props, "Memory ", memoryStatsGetter.get().toJsonStr()); 57 | addJsonContent(props, "Thread ", threadStatsGetter.get().toJsonStr()); 58 | addJsonContent(props, "Class ", classStatsGetter.get().toJsonStr()); 59 | addJsonContent(props, "GC(last Minute) ", statusInfo.getGCStats().toJsonStr()); 60 | 61 | String jsonStr = JSON.toJSONString(props); 62 | 63 | resp.addHeader("Access-Control-Allow-Origin", "*"); 64 | resp.addHeader("Access-Control-Allow-Headers","Content-Type, Accept"); 65 | resp.setContentType("application/json; charset=UTF-8"); 66 | 67 | PrintWriter writer = resp.getWriter(); 68 | try{ 69 | writer.write(jsonStr); 70 | resp.setStatus(Response.SC_OK); 71 | } finally { 72 | if (writer != null) { 73 | writer.close(); 74 | } 75 | } 76 | } 77 | 78 | private void addJsonContent(Map props, String prefix, String jsonContent) throws IOException { 79 | Map m = JSON.parseObject(jsonContent, Map.class); 80 | //mapper.readValue(jsonContent, Map.class); 81 | for (Map.Entry entry : m.entrySet()) { 82 | props.put(prefix + entry.getKey(), (String) entry.getValue()); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/stat/ClassStatsGetter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.stat; 2 | 3 | import java.lang.management.ClassLoadingMXBean; 4 | import java.lang.management.ManagementFactory; 5 | 6 | import io.spring2go.tools.common.ClassStats; 7 | import io.spring2go.tools.common.Stats; 8 | import io.spring2go.tools.common.StatsGetter; 9 | 10 | 11 | public class ClassStatsGetter implements StatsGetter { 12 | ClassLoadingMXBean bean = ManagementFactory.getClassLoadingMXBean(); 13 | @Override 14 | public Stats get() { 15 | ClassStats s = new ClassStats(); 16 | s.setCurrentClassCount(bean.getLoadedClassCount()); 17 | s.setBeenLoadedClassCount(bean.getTotalLoadedClassCount()); 18 | s.setBeenUnloadedClassCount(bean.getUnloadedClassCount()); 19 | return s; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/stat/GCStatsGetter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.stat; 2 | 3 | import java.lang.management.GarbageCollectorMXBean; 4 | import java.lang.management.ManagementFactory; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import io.spring2go.tools.common.GCStats; 9 | import io.spring2go.tools.common.Stats; 10 | import io.spring2go.tools.common.StatsGetter; 11 | 12 | 13 | public class GCStatsGetter implements StatsGetter { 14 | String[] youngGenCollectorNames = new String[]{ 15 | // Oracle (Sun) HotSpot 16 | // -XX:+UseSerialGC 17 | "Copy", 18 | // -XX:+UseParNewGC 19 | "ParNew", 20 | // -XX:+UseParallelGC 21 | "PS Scavenge", 22 | 23 | // Oracle (BEA) JRockit 24 | // -XgcPrio:pausetime 25 | "Garbage collection optimized for short pausetimes Young Collector", 26 | // -XgcPrio:throughput 27 | "Garbage collection optimized for throughput Young Collector", 28 | // -XgcPrio:deterministic 29 | "Garbage collection optimized for deterministic pausetimes Young Collector" 30 | }; 31 | 32 | String[] oldGenCollectorNames = new String[]{ 33 | // Oracle (Sun) HotSpot 34 | // -XX:+UseSerialGC 35 | "MarkSweepCompact", 36 | // -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting) 37 | "PS MarkSweep", 38 | // -XX:+UseConcMarkSweepGC 39 | "ConcurrentMarkSweep", 40 | 41 | // Oracle (BEA) JRockit 42 | // -XgcPrio:pausetime 43 | "Garbage collection optimized for short pausetimes Old Collector", 44 | // -XgcPrio:throughput 45 | "Garbage collection optimized for throughput Old Collector", 46 | // -XgcPrio:deterministic 47 | "Garbage collection optimized for deterministic pausetimes Old Collector" 48 | }; 49 | 50 | List young = Arrays.asList(youngGenCollectorNames); 51 | List old = Arrays.asList(oldGenCollectorNames); 52 | 53 | GCStats previous = new GCStats(); 54 | 55 | @Override 56 | public Stats get() { 57 | 58 | List beans = ManagementFactory.getGarbageCollectorMXBeans(); 59 | int minorGcCount=0, fullGcCount=0, otherGcCount=0; 60 | long minorGcTime=0, fullGcTime=0, otherGcTime=0; 61 | for (GarbageCollectorMXBean b : beans) { 62 | String name = b.getName(); 63 | if (young.contains(name)) { 64 | minorGcCount += b.getCollectionCount(); 65 | minorGcTime += b.getCollectionTime(); 66 | }else if (old.contains(name)) { 67 | fullGcCount += b.getCollectionCount(); 68 | fullGcTime += b.getCollectionTime(); 69 | }else{ 70 | otherGcCount += b.getCollectionCount(); 71 | otherGcTime += b.getCollectionTime(); 72 | } 73 | } 74 | 75 | GCStats s = new GCStats(); 76 | s.setMinorGcCount(minorGcCount - previous.getMinorGcCount()); 77 | s.setMinorGcTime(minorGcTime - previous.getMinorGcTime()); 78 | s.setFullGcCount(fullGcCount - previous.getFullGcCount()); 79 | s.setFullGcTime(fullGcTime - previous.getFullGcTime()); 80 | s.setOtherGcCount(otherGcCount - previous.getOtherGcCount()); 81 | s.setOtherGcCount(otherGcTime - previous.getOtherGcTime()); 82 | 83 | previous.setMinorGcCount(minorGcCount); 84 | previous.setMinorGcTime(minorGcTime); 85 | previous.setFullGcCount(fullGcCount); 86 | previous.setFullGcTime(fullGcTime); 87 | previous.setOtherGcCount(otherGcCount); 88 | previous.setOtherGcCount(otherGcTime); 89 | 90 | return s; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/stat/JvmStatsReporter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.stat; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.CopyOnWriteArrayList; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import io.spring2go.tools.common.Stats; 11 | import io.spring2go.tools.common.StatsGetter; 12 | import io.spring2go.tools.common.StatsHandler; 13 | 14 | 15 | public class JvmStatsReporter { 16 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | 18 | private volatile boolean running = false; 19 | private Thread workThread; 20 | private volatile long reportInterval = 1000*60; 21 | 22 | private String name; 23 | 24 | private List statsGetterList = new CopyOnWriteArrayList(); 25 | private List statsHandlerList = new CopyOnWriteArrayList(); 26 | 27 | public JvmStatsReporter(String name, long interval) { 28 | this.name = name; 29 | this.reportInterval = interval; 30 | 31 | statsGetterList.add(new ClassStatsGetter()); 32 | statsGetterList.add(new ThreadStatsGetter()); 33 | statsGetterList.add(new MemoryStatsGetter()); 34 | statsGetterList.add(new GCStatsGetter()); 35 | statsGetterList.add(new OperatingSystemStatsGetter()); 36 | 37 | //statsHandlerList.add(new LogHandler()); 38 | } 39 | 40 | synchronized public void start() { 41 | if (!running) { 42 | running = true; 43 | workThread = newWorkThread(); 44 | workThread.start(); 45 | } 46 | 47 | } 48 | 49 | synchronized public void shutdown() { 50 | if (running) { 51 | running = false; 52 | workThread = null; 53 | } 54 | } 55 | 56 | public boolean isRunning(){ 57 | return running; 58 | } 59 | 60 | public void setReportInterval(long reportInterval) { 61 | if (reportInterval > 0) { 62 | this.reportInterval = reportInterval; 63 | } 64 | } 65 | 66 | private Thread newWorkThread() { 67 | final String reporterName = this.getClass().getSimpleName(); 68 | return new Thread(reporterName + "-Thread") { 69 | public void run() { 70 | try { 71 | while (running) { 72 | try { 73 | for (StatsGetter getter : statsGetterList) { 74 | Stats s = getter.get(); 75 | for (StatsHandler handler : statsHandlerList) { 76 | handler.process(s); 77 | } 78 | } 79 | 80 | } catch (Throwable e) { 81 | logger.error("Encounter an error while reporting.", e); 82 | } finally { 83 | sleep(reportInterval); 84 | } 85 | } 86 | } catch (InterruptedException e) { 87 | logger.error(reporterName + " stopped because some error.", e); 88 | } 89 | } 90 | 91 | }; 92 | } 93 | 94 | public void addStatsGetter(StatsGetter getter){ 95 | statsGetterList.add(getter); 96 | } 97 | 98 | public void removeStatsGetter(StatsGetter getter){ 99 | while(statsGetterList.remove(getter)); 100 | } 101 | 102 | public List getAllStatsGetter(){ 103 | return new ArrayList(statsGetterList); 104 | } 105 | 106 | public void emptyStatsGetter(){ 107 | statsGetterList.clear(); 108 | } 109 | 110 | public void addStatsHandler(StatsHandler handler){ 111 | statsHandlerList.add(handler); 112 | } 113 | 114 | public void removeStatsHandler(StatsHandler handler){ 115 | while(statsHandlerList.remove(handler)); 116 | } 117 | 118 | public List getAllStatsHandler(){ 119 | return new ArrayList(statsHandlerList); 120 | } 121 | 122 | public void emtyStatsHandler(){ 123 | statsHandlerList.clear(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/stat/MemoryStatsGetter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.stat; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.MemoryMXBean; 5 | import java.lang.management.MemoryUsage; 6 | 7 | import io.spring2go.tools.common.MemoryStats; 8 | import io.spring2go.tools.common.Stats; 9 | import io.spring2go.tools.common.StatsGetter; 10 | 11 | 12 | public class MemoryStatsGetter implements StatsGetter { 13 | MemoryMXBean bean = ManagementFactory.getMemoryMXBean(); 14 | 15 | @Override 16 | public Stats get() { 17 | MemoryStats s = new MemoryStats(); 18 | 19 | MemoryUsage u = bean.getHeapMemoryUsage(); 20 | s.setHeapCommitedMemory(u.getCommitted()); 21 | s.setHeapUsedMemory(u.getUsed()); 22 | s.setHeapMaxMemory(u.getMax()); 23 | 24 | u = bean.getNonHeapMemoryUsage(); 25 | s.setNonHeapCommitedMemory(u.getCommitted()); 26 | s.setNonHeapUsedMemory(u.getUsed()); 27 | s.setNonHeapMaxMemory(u.getMax()); 28 | 29 | return s; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/stat/ThreadStatsGetter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.stat; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.ThreadMXBean; 5 | 6 | import io.spring2go.tools.common.Stats; 7 | import io.spring2go.tools.common.StatsGetter; 8 | import io.spring2go.tools.common.ThreadStats; 9 | 10 | 11 | public class ThreadStatsGetter implements StatsGetter { 12 | ThreadMXBean bean = ManagementFactory.getThreadMXBean(); 13 | 14 | @Override 15 | public Stats get() { 16 | ThreadStats s = new ThreadStats(); 17 | s.setCurrentThreadCount(bean.getThreadCount()); 18 | s.setDaemonThreadCount(bean.getDaemonThreadCount()); 19 | s.setBeenCreatedThreadCount(bean.getTotalStartedThreadCount()); 20 | return s; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/util/ByteUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.util; 2 | 3 | public class ByteUtil { 4 | 5 | public static String bytesToSize(long bytes) { 6 | long kilobyte = 1024; 7 | long megabyte = kilobyte * 1024; 8 | long gigabyte = megabyte * 1024; 9 | long terabyte = gigabyte * 1024; 10 | 11 | if ((bytes >= 0) && (bytes < kilobyte)) { 12 | return bytes + " B"; 13 | 14 | } else if ((bytes >= kilobyte) && (bytes < megabyte)) { 15 | return String.format("%.0f", (double) bytes / kilobyte) + " KB"; 16 | 17 | } else if ((bytes >= megabyte) && (bytes < gigabyte)) { 18 | return String.format("%.2f", (double)bytes / megabyte) + " MB"; 19 | 20 | } else if ((bytes >= gigabyte) && (bytes < terabyte)) { 21 | return String.format("%.2f", (double)bytes / gigabyte) + " GB"; 22 | 23 | } else if (bytes >= terabyte) { 24 | return String.format("%.2f", (double)bytes / terabyte) + " TB"; 25 | 26 | } else { 27 | return bytes + " B"; 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/tools/util/TimeUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.tools.util; 2 | 3 | public class TimeUtil { 4 | 5 | public static String readableTimeInterval(long uptime) { 6 | long year = uptime/(1000*60*60*24*365); 7 | long month = (uptime%(1000*60*60*24*365))/(1000*60*60*24*30); 8 | long day = ((uptime%(1000*60*60*24*365))%(1000*60*60*24*30))/(1000*60*60*24); 9 | long hour = (uptime%(1000*60*60*24))/(1000*60*60); 10 | long minute = (uptime%(1000*60*60))/(1000*60); 11 | long second = (uptime%(1000*60))/(1000); 12 | 13 | StringBuilder builder = new StringBuilder(" "); 14 | if(year > 0) builder.append(year).append(year>1?" Years " : " Year "); 15 | if(month > 0) builder.append(month).append(month>1?" Months " : " Month "); 16 | if(day > 0) builder.append(day).append(day>1?" Days " : " Day "); 17 | if(hour > 0) builder.append(hour).append(hour>1?" Hours " : " Hour "); 18 | if(minute > 0) builder.append(minute).append(minute>1?" Minutes " : " Minute "); 19 | if(second > 0) builder.append(second).append(second>1?" Seconds " : " Second "); 20 | 21 | return builder.toString(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/CatContext.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.dianping.cat.Cat; 7 | 8 | public class CatContext implements Cat.Context { 9 | private Map properties = new HashMap(); 10 | 11 | @Override 12 | public void addProperty(String key, String value) { 13 | this.properties.put(key, value); 14 | } 15 | 16 | @Override 17 | public String getProperty(String key) { 18 | return this.properties.get(key); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/Constants.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public class Constants { 4 | 5 | // config items 6 | public static final String APPLICATION_NAME = "zuul-gateway"; 7 | public static final String DEPLOYMENT_APPLICATION_ID = "archaius.deployment.applicationId"; 8 | public static final String DEPLOY_CONFIG_URL = "archaius.configurationSource.additionalUrls"; 9 | public static final String DEPLOY_ENVIRONMENT = "archaius.deployment.environment"; 10 | 11 | public static final String DATA_SOURCE_CLASS_NAME = "zuul.data-source.class-name"; 12 | public static final String DATA_SOURCE_URL = "zuul.data-source.url"; 13 | public static final String DATA_SOURCE_USER = "zuul.data-source.user"; 14 | public static final String DATA_SOURCE_PASSWORD = "zuul.data-source.password"; 15 | public static final String DATA_SOURCE_MIN_POOL_SIZE = "zuul.data-source.min-pool-size"; 16 | public static final String DATA_SOURCE_MAX_POOL_SIZE = "zuul.data-source.max-pool-size"; 17 | public static final String DATA_SOURCE_CONNECT_TIMEOUT = "zuul.data-source.connection-timeout"; 18 | public static final String DATA_SOURCE_IDLE_TIMEOUT = "zuul.data-source.idle-timeout"; 19 | public static final String DATA_SOURCE_MAX_LIFETIME = "zuul.data-source.max-lifetime"; 20 | 21 | public static final String FILTER_TABLE_NAME = "zuul.filter.table.name"; 22 | public static final String ZUUL_FILTER_DAO_TYPE = "zuul.filter.dao.type"; 23 | public static final String ZUUL_FILTER_REPO = "zuul.filter.repository"; 24 | 25 | public static final String ZUUL_FILTER_ADMIN_ENABLED = "zuul.filter.admin.enabled"; 26 | 27 | public static final String ZUUL_FILTER_POLLER_ENABLED = "zuul.filter.poller.enabled"; 28 | public static final String ZUUL_FILTER_POLLER_INTERVAL = "zuul.filter.poller.interval"; 29 | 30 | public static final String ZUUL_USE_ACTIVE_FILTERS = "zuul.use.active.filters"; 31 | public static final String ZUUL_USE_CANARY_FILTERS = "zuul.use.canary.filters"; 32 | 33 | public static final String ZUUL_FILTER_PRE_PATH = "zuul.filter.pre.path"; 34 | public static final String ZUUL_FILTER_ROUTE_PATH = "zuul.filter.route.path"; 35 | public static final String ZUUL_FILTER_POST_PATH = "zuul.filter.post.path"; 36 | public static final String ZUUL_FILTER_ERROR_PATH = "zuul.filter.error.path"; 37 | public static final String Zuul_FILTER_CUSTOM_PATH = "zuul.filter.custom.path"; 38 | 39 | public static final String ZUUL_SERVLET_ASYNC_TIMEOUT = "zuul.servlet.async.timeout"; 40 | public static final String ZUUL_THREADPOOL_CODE_SIZE = "zuul.thread-pool.core-size"; 41 | public static final String ZUUL_THREADPOOL_MAX_SIZE = "zuul.thread-pool.maximum-size"; 42 | public static final String ZUUL_THREADPOOL_ALIVE_TIME = "zuul.thread-pool.alive-time"; 43 | 44 | public static final String ZUUL_INITIAL_STREAM_BUFFER_SIZE = "zuul.initial-stream-buffer-size"; 45 | public static final String ZUUL_SET_CONTENT_LENGTH = "zuul.set-content-length"; 46 | 47 | public static final String ZUUL_CLIENT_MAX_CONNECTIONS = "zuul.client.max.connections"; 48 | public static final String ZUUL_CLIENT_ROUTE_MAX_CONNECTIONS = "zuul.client.route.max.connections"; 49 | 50 | public static final String DEFAULT_GROUP = "default-group"; 51 | public static final String DEFAULT_NAME = "default-name"; 52 | // public static final String DEFAULT_DOMAIN = "default-domain"; 53 | 54 | // public static final String ZUUL_ROUTE_POLLER_ENABLED = "zuul.route.poller.enabled"; 55 | // public static final String ZUUL_ROUTE_POLLER_INTERVAL = "zuul.route.poller.interval"; 56 | // public static final String ZUUL_ROUTE_POLLER_URL = "zuul.route.poller.url"; 57 | // constants 58 | public static final String CAT_CHILD_MESSAGE_ID = "X-CAT-CHILD-ID"; 59 | public static final String CAT_PARENT_MESSAGE_ID = "X-CAT-PARENT-ID"; 60 | public static final String CAT_ROOT_MESSAGE_ID = "X-CAT-ROOT-ID"; 61 | public static final String CAT_S2G_APP = "X-S2G-CAT-APP"; 62 | public static final String HTTP_ERROR_CODE_HEADER = "X-S2G-CODE"; 63 | public static final String HTTP_ERROR_MESSAGE_HEADER = "X-S2G-MESSAGE"; 64 | public static final String HTTP_S2G_DOMAIN = "X-S2G-DOMAIN"; 65 | public static final String HTTP_S2G_SERVICEID = "X-S2G-SERVICE"; 66 | 67 | // public static final String GAETEWAY_DATA = "GatewayData"; 68 | 69 | 70 | public static final String ZUUL_DEBUG_REQUEST = "zuul.debug.request"; 71 | public static final String ZUUL_DEBUG_PARAMETER = "zuul.debug.parameter"; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/ExecutionStatus.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public enum ExecutionStatus { 4 | 5 | SUCCESS(1), SKIPPED(-1), DISABLED(-2), FAILED(-3); 6 | 7 | private int status; 8 | 9 | ExecutionStatus(int status) { 10 | this.status = status; 11 | } 12 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/HttpServletResponseWrapper.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import javax.servlet.http.HttpServletResponse; 4 | 5 | /** 6 | * ServletResponseWrapper which delegates all to underlying ServletResponse, 7 | * except for: 8 | *
    9 | *
  • Records the status code set on the response.
  • 10 | *
11 | * 12 | * 13 | */ 14 | public class HttpServletResponseWrapper extends javax.servlet.http.HttpServletResponseWrapper { 15 | private int status = 0; 16 | 17 | public HttpServletResponseWrapper(HttpServletResponse response) { 18 | super(response); 19 | } 20 | 21 | @Override 22 | public void setStatus(int sc) { 23 | this.status = sc; 24 | super.setStatus(sc); 25 | } 26 | 27 | @Override 28 | public void setStatus(int sc, String sm) { 29 | this.status = sc; 30 | super.setStatus(sc, sm); 31 | } 32 | 33 | public int getStatus() { 34 | return status; 35 | } 36 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IDynamicCodeCompiler.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import java.io.File; 4 | 5 | 6 | /** 7 | * Interface to generate Classes from source code 8 | */ 9 | public interface IDynamicCodeCompiler { 10 | Class compile(String sCode, String sName) throws Exception; 11 | 12 | Class compile(File file) throws Exception; 13 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IFilterFactory.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import io.spring2go.zuul.filters.ZuulFilter; 4 | 5 | /** 6 | * Interface to provide instances of ZuulFilter from a given class. 7 | */ 8 | public interface IFilterFactory { 9 | 10 | /** 11 | * Returns an instance of the specified class. 12 | * 13 | * @param clazz 14 | * the Class to instantiate 15 | * @return an instance of ZuulFilter 16 | * @throws Exception 17 | * if an error occurs 18 | */ 19 | public ZuulFilter newInstance(Class clazz) throws Exception; 20 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IFilterUsageNotifier.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import io.spring2go.zuul.filters.ZuulFilter; 4 | 5 | /** 6 | * Interface to implement for registering a callback for each time a filter 7 | * is used. 8 | * 9 | */ 10 | public interface IFilterUsageNotifier { 11 | public void notify(ZuulFilter filter, ExecutionStatus status); 12 | } 13 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IMonitor.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public interface IMonitor { 4 | /** 5 | * Implement this to add this Counter to a Registry 6 | * @param monitorObj 7 | */ 8 | void register(INamedCount monitorObj); 9 | } 10 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/INamedCount.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public interface INamedCount { 4 | 5 | public String getName(); 6 | public long getCount(); 7 | 8 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/ITracer.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | /** 3 | * Time based monitoring metric. 4 | * 5 | */ 6 | public interface ITracer { 7 | 8 | /** 9 | * Stops and Logs a time based tracer 10 | * 11 | */ 12 | void stopAndLog(); 13 | 14 | /** 15 | * Sets the name for the time based tracer 16 | * 17 | * @param name a String value 18 | */ 19 | void setName(String name); 20 | 21 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IZuulFilter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public interface IZuulFilter { 4 | 5 | /** 6 | * a "true" return from this method means that the run() method should be invoked 7 | * 8 | * @return true if the run() method should be invoked. false will not invoke the run() method 9 | */ 10 | boolean shouldFilter(); 11 | 12 | /** 13 | * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter 14 | * 15 | * @return Some arbitrary artifact may be returned. Current implementation ignores it. 16 | */ 17 | Object run() throws ZuulException; 18 | 19 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IZuulFilterDao.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Interface for data access to persist filters in a persistent store 7 | * 8 | */ 9 | public interface IZuulFilterDao { 10 | /** 11 | * 12 | * @return a list of all filterIds 13 | */ 14 | List getAllFilterIds() throws Exception; 15 | 16 | /** 17 | * returns all filter revisions for the given filterId 18 | * @param filterId 19 | * @return returns all filter revisions for the given filterId 20 | */ 21 | List getZuulFilters(String filterId) throws Exception; 22 | 23 | /** 24 | * 25 | * @param filterId 26 | * @param revision 27 | * @return returns a specific revision for a filter 28 | */ 29 | FilterInfo getFilter(String filterId, int revision) throws Exception; 30 | 31 | /** 32 | * 33 | * @param filterId 34 | * @return returns the latest version of a given filter 35 | */ 36 | FilterInfo getLatestFilter(String filterId) throws Exception; 37 | 38 | /** 39 | * returns the active filter for a given filterId 40 | * @param filterId 41 | * @return 42 | */ 43 | FilterInfo getActiveFilter(String filterId) throws Exception; 44 | 45 | /** 46 | * 47 | * @return all filters active in the "canary" mode 48 | */ 49 | List getAllCanaryFilters() throws Exception; 50 | 51 | /** 52 | * 53 | * @return all active filters 54 | */ 55 | List getAllActiveFilters() throws Exception; 56 | 57 | /** 58 | * sets a filter and revision as active in a "canary" 59 | * @param filterId 60 | * @param revision 61 | * @return the filter 62 | */ 63 | FilterInfo canaryFilter(String filterId, int revision) throws Exception; 64 | 65 | 66 | /** 67 | * sets a filter and revision as active 68 | * @param filterId 69 | * @param revision 70 | * @return the filter 71 | * @throws Exception 72 | */ 73 | FilterInfo activateFilter(String filterId, int revision) throws Exception; 74 | 75 | /** 76 | * Deactiviates a filter; removes it from being active. 77 | * @param filterId 78 | * @param revision 79 | * @return the filter 80 | * @throws Exception 81 | */ 82 | FilterInfo deactivateFilter(String filterId, int revision) throws Exception; 83 | 84 | /** 85 | * adds a new filter to the persistent store 86 | * @param filterCode 87 | * @param filterType 88 | * @param filterName 89 | * @param filterDisablePropertyName 90 | * @param filterOrder 91 | * @return the filter 92 | */ 93 | FilterInfo addFilter(String filterCode, String filterType, String filterName, String filterDisablePropertyName, String filterOrder) throws Exception; 94 | 95 | /** 96 | * 97 | * @param index 98 | * @return all filter_ids for a given index as a | delimited list 99 | */ 100 | String getFilterIdsRaw(String index); 101 | 102 | /** 103 | * 104 | * @param index 105 | * @return returns filter_ids for a given index as a parsed list 106 | */ 107 | List getFilterIdsIndex(String index); 108 | 109 | /** 110 | * close connection 111 | */ 112 | void close(); 113 | 114 | } 115 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/IZuulFilterDaoBuilder.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public interface IZuulFilterDaoBuilder { 4 | IZuulFilterDao build(); 5 | } 6 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/ServletInputStreamWrapper.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | import java.io.IOException; 4 | import javax.servlet.ServletInputStream; 5 | /** 6 | * ServletInputStream wrapper to wrap a byte[] into a ServletInputStream 7 | * 8 | */ 9 | public class ServletInputStreamWrapper extends ServletInputStream { 10 | 11 | private byte[] data; 12 | private int idx = 0; 13 | 14 | /** 15 | * Creates a new ServletInputStreamWrapper instance. 16 | * 17 | * @param data a byte[] value 18 | */ 19 | public ServletInputStreamWrapper(byte[] data) { 20 | if (data == null) 21 | data = new byte[0]; 22 | this.data = data; 23 | } 24 | 25 | @Override 26 | public int read() throws IOException { 27 | if (idx == data.length) 28 | return -1; 29 | // I have to AND the byte with 0xff in order to ensure that it is returned as an unsigned integer 30 | // the lack of this was causing a weird bug when manually unzipping gzipped request bodies 31 | return data[idx++] & 0xff; 32 | } 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/ZuulException.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | /** 3 | * All handled exceptions in Zuul are ZuulExceptions 4 | */ 5 | public class ZuulException extends Exception { 6 | public int nStatusCode; 7 | public String errorCause; 8 | 9 | /** 10 | * Source Throwable, message, status code and info about the cause 11 | * @param throwable 12 | * @param sMessage 13 | * @param nStatusCode 14 | * @param errorCause 15 | */ 16 | public ZuulException(Throwable throwable, String sMessage, int nStatusCode, String errorCause) { 17 | super(sMessage, throwable); 18 | this.nStatusCode = nStatusCode; 19 | this.errorCause = errorCause; 20 | } 21 | 22 | /** 23 | * error message, status code and info about the cause 24 | * @param sMessage 25 | * @param nStatusCode 26 | * @param errorCause 27 | */ 28 | public ZuulException(String sMessage, int nStatusCode, String errorCause) { 29 | super(sMessage); 30 | this.nStatusCode = nStatusCode; 31 | this.errorCause = errorCause; 32 | } 33 | 34 | /** 35 | * Source Throwable, status code and info about the cause 36 | * @param throwable 37 | * @param nStatusCode 38 | * @param errorCause 39 | */ 40 | public ZuulException(Throwable throwable, int nStatusCode, String errorCause) { 41 | super(throwable.getMessage(), throwable); 42 | this.nStatusCode = nStatusCode; 43 | this.errorCause = errorCause; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/ZuulFilterResult.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | public final class ZuulFilterResult { 4 | 5 | private Object result; 6 | private Throwable exception; 7 | private ExecutionStatus status; 8 | 9 | public ZuulFilterResult(Object result, ExecutionStatus status) { 10 | this.result = result; 11 | this.status = status; 12 | } 13 | 14 | public ZuulFilterResult(ExecutionStatus status) { 15 | this.status = status; 16 | } 17 | 18 | public ZuulFilterResult() { 19 | this.status = ExecutionStatus.DISABLED; 20 | } 21 | 22 | /** 23 | * @return the result 24 | */ 25 | public Object getResult() { 26 | return result; 27 | } 28 | 29 | /** 30 | * @param result 31 | * the result to set 32 | */ 33 | public void setResult(Object result) { 34 | this.result = result; 35 | } 36 | 37 | /** 38 | * @return the status 39 | */ 40 | public ExecutionStatus getStatus() { 41 | return status; 42 | } 43 | 44 | /** 45 | * @param status 46 | * the status to set 47 | */ 48 | public void setStatus(ExecutionStatus status) { 49 | this.status = status; 50 | } 51 | 52 | /** 53 | * @return the exception 54 | */ 55 | public Throwable getException() { 56 | return exception; 57 | } 58 | 59 | /** 60 | * @param exception 61 | * the exception to set 62 | */ 63 | public void setException(Throwable exception) { 64 | this.exception = exception; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/common/ZuulHeaders.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.common; 2 | 3 | /** 4 | * HTTP Headers that are accessed or added by Spring2go Zuul Gateway 5 | */ 6 | public class ZuulHeaders { 7 | public static final String TRANSFER_ENCODING = "transfer-encoding"; 8 | public static final String CHUNKED = "chunked"; 9 | public static final String CONTENT_ENCODING = "content-encoding"; 10 | public static final String CONTENT_LENGTH = "content-length"; 11 | public static final String ACCEPT_ENCODING = "accept-encoding"; 12 | public static final String CONNECTION = "connection"; 13 | public static final String KEEP_ALIVE = "keep-alive"; 14 | public static final String HOST = "host"; 15 | public static final String X_FORWARDED_PROTO = "x-forwarded-proto"; 16 | public static final String X_FORWARDED_FOR = "x-forwarded-for"; 17 | 18 | public static final String X_ZUUL = "x-zuul"; 19 | public static final String X_ZUUL_INSTANCE = "x-zuul-instance"; 20 | public static final String X_ORIGINATING_URL = "x-originating-url"; 21 | public static final String X_ZUUL_ERROR_CAUSE = "x-zuul-error-cause"; 22 | public static final String X_ZUUL_CLIENT_HOST = "x-zuul-client-host"; 23 | public static final String X_ZUUL_CLIENT_PROTO = "x-zuul-client-proto"; 24 | public static final String X_ZUUL_SURGICAL_FILTER = "x-zuul-surgical-filter"; 25 | public static final String X_ZUUL_FILTER_EXECUTION_STATUS = "x-zuul-filter-executions"; 26 | public static final String X_ZUUL_REQUEST_TOPLEVEL_ID = "x-zuul-request.toplevel.uuid"; 27 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/core/LogConfigurator.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.core; 2 | 3 | import java.io.InputStream; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import ch.qos.logback.classic.LoggerContext; 9 | import ch.qos.logback.classic.joran.JoranConfigurator; 10 | import ch.qos.logback.core.joran.spi.JoranException; 11 | import ch.qos.logback.core.util.StatusPrinter; 12 | 13 | public class LogConfigurator { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(LogConfigurator.class); 15 | private String appName; 16 | private String environment; 17 | 18 | public LogConfigurator(String appName, String environment) { 19 | this.appName = appName; 20 | this.environment = environment; 21 | } 22 | 23 | public void config() { 24 | LOGGER.info("To reconfigure logback."); 25 | try { 26 | LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 27 | try { 28 | JoranConfigurator joranConfigurator = new JoranConfigurator(); 29 | joranConfigurator.setContext(lc); 30 | lc.reset(); 31 | 32 | 33 | String configFileName = appName + "-logback" + (environment != null ? "-" + environment : "") + ".xml"; 34 | InputStream inputStream = LogConfigurator.class.getClassLoader().getResourceAsStream(configFileName); 35 | 36 | if (inputStream == null) { 37 | throw new Exception("Can't find the logback config file [ " + configFileName + " ]."); 38 | } 39 | 40 | joranConfigurator.doConfigure(inputStream); 41 | 42 | LOGGER.info("Reconfigure logback."); 43 | } catch (JoranException e) { 44 | e.printStackTrace(); 45 | } 46 | StatusPrinter.printInCaseOfErrorsOrWarnings(lc); 47 | } catch (Exception e) { 48 | LOGGER.warn("Failed to reconfigure logback.", e); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/core/ZuulRunner.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.core; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import io.spring2go.zuul.common.ZuulException; 7 | import io.spring2go.zuul.common.HttpServletRequestWrapper; 8 | import io.spring2go.zuul.common.HttpServletResponseWrapper; 9 | import io.spring2go.zuul.context.RequestContext; 10 | 11 | /** 12 | * This class initializes servlet requests and responses into the RequestContext 13 | * and wraps the FilterProcessor calls to preRoute(), route(), postRoute(), and 14 | * error() methods 15 | * 16 | */ 17 | public class ZuulRunner { 18 | 19 | /** 20 | * Creates a new ZuulRunner instance. 21 | */ 22 | public ZuulRunner() { 23 | } 24 | 25 | /** 26 | * sets HttpServlet request and HttpResponse 27 | * 28 | * @param servletRequest 29 | * @param servletResponse 30 | */ 31 | public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { 32 | RequestContext.getCurrentContext().setRequest(new HttpServletRequestWrapper(servletRequest)); 33 | RequestContext.getCurrentContext().setResponse(new HttpServletResponseWrapper(servletResponse)); 34 | } 35 | 36 | /** 37 | * executes "pre" filterType ZuulFilters 38 | * 39 | * @throws ZuulException 40 | */ 41 | public void preRoute() throws ZuulException { 42 | FilterProcessor.getInstance().preRoute(); 43 | } 44 | 45 | /** 46 | * executes "route" filterType ZuulFilters 47 | * 48 | * @throws ZuulException 49 | */ 50 | public void route() throws ZuulException { 51 | FilterProcessor.getInstance().route(); 52 | } 53 | 54 | /** 55 | * executes "post" filterType ZuulFilters 56 | * 57 | * @throws ZuulException 58 | */ 59 | public void postRoute() throws ZuulException { 60 | FilterProcessor.getInstance().postRoute(); 61 | } 62 | 63 | /** 64 | * executes "error" filterType ZuulFilters 65 | * @throws ZuulException 66 | */ 67 | public void error() throws ZuulException { 68 | FilterProcessor.getInstance().error(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/DefaultFilterFactory.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import io.spring2go.zuul.common.IFilterFactory; 4 | 5 | /** 6 | * Default factory for creating instances of ZuulFilter. 7 | */ 8 | public class DefaultFilterFactory implements IFilterFactory { 9 | 10 | /** 11 | * Returns a new implementation of ZuulFilter as specified by the provided 12 | * Class. The Class is instantiated using its nullary constructor. 13 | * 14 | * @param clazz the Class to instantiate 15 | * @return A new instance of ZuulFilter 16 | */ 17 | @Override 18 | public ZuulFilter newInstance(Class clazz) throws InstantiationException, IllegalAccessException { 19 | return (ZuulFilter) clazz.newInstance(); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/FilterRegistry.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import java.util.Collection; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | public class FilterRegistry { 7 | 8 | private static final FilterRegistry instance = new FilterRegistry(); 9 | 10 | public static final FilterRegistry instance() { 11 | return instance; 12 | } 13 | 14 | private final ConcurrentHashMap filters = new ConcurrentHashMap(); 15 | 16 | private FilterRegistry() { 17 | } 18 | 19 | public ZuulFilter remove(String key) { 20 | return this.filters.remove(key); 21 | } 22 | 23 | public ZuulFilter get(String key) { 24 | return this.filters.get(key); 25 | } 26 | 27 | public void put(String key, ZuulFilter filter) { 28 | this.filters.putIfAbsent(key, filter); 29 | } 30 | 31 | public int size() { 32 | return this.filters.size(); 33 | } 34 | 35 | public Collection getAllFilters() { 36 | return this.filters.values(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/FilterVerifier.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import io.spring2go.zuul.common.Constants; 4 | import io.spring2go.zuul.common.FilterInfo; 5 | 6 | import groovy.lang.GroovyClassLoader; 7 | 8 | /** 9 | * verifies that the given source code is compilable in Groovy, can be 10 | * instanciated, and is a ZuulFilter type 11 | * 12 | */ 13 | public class FilterVerifier { 14 | private static final FilterVerifier instance = new FilterVerifier(); 15 | 16 | /** 17 | * @return Singleton 18 | */ 19 | public static FilterVerifier getInstance() { 20 | return instance; 21 | } 22 | 23 | /** 24 | * verifies compilation, instanciation and that it is a ZuulFilter 25 | * 26 | * @param sFilterCode 27 | * @return a FilterInfo object representing that code 28 | * @throws org.codehaus.groovy.control.CompilationFailedException 29 | * 30 | * @throws IllegalAccessException 31 | * @throws InstantiationException 32 | */ 33 | public FilterInfo verifyFilter(String sFilterCode) throws org.codehaus.groovy.control.CompilationFailedException, 34 | IllegalAccessException, InstantiationException { 35 | Class groovyClass = compileGroovy(sFilterCode); 36 | Object instance = instanciateClass(groovyClass); 37 | checkZuulFilterInstance(instance); 38 | ZuulFilter filter = (ZuulFilter) instance; 39 | 40 | String filter_id = FilterInfo.buildFilterId(Constants.APPLICATION_NAME, filter.filterType(), 41 | groovyClass.getSimpleName()); 42 | 43 | return new FilterInfo(filter_id, sFilterCode, filter.filterType(), groovyClass.getSimpleName(), 44 | filter.disablePropertyName(), "" + filter.filterOrder(), Constants.APPLICATION_NAME); 45 | } 46 | 47 | Object instanciateClass(Class groovyClass) throws InstantiationException, IllegalAccessException { 48 | return groovyClass.newInstance(); 49 | } 50 | 51 | void checkZuulFilterInstance(Object zuulFilter) throws InstantiationException { 52 | if (!(zuulFilter instanceof ZuulFilter)) { 53 | throw new InstantiationException("Code is not a ZuulFilter Class "); 54 | } 55 | } 56 | 57 | /** 58 | * compiles the Groovy source code 59 | * 60 | * @param sFilterCode 61 | * @return 62 | * @throws org.codehaus.groovy.control.CompilationFailedException 63 | * 64 | */ 65 | public Class compileGroovy(String sFilterCode) throws org.codehaus.groovy.control.CompilationFailedException { 66 | GroovyClassLoader loader = new GroovyClassLoader(); 67 | return loader.parseClass(sFilterCode); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/HttpZuulFilterDaoBuilder.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import com.netflix.config.DynamicPropertyFactory; 4 | import com.netflix.config.DynamicStringProperty; 5 | import io.spring2go.zuul.common.Constants; 6 | import io.spring2go.zuul.common.IZuulFilterDao; 7 | import io.spring2go.zuul.common.IZuulFilterDaoBuilder; 8 | 9 | public class HttpZuulFilterDaoBuilder implements IZuulFilterDaoBuilder { 10 | 11 | private static final DynamicStringProperty appName = DynamicPropertyFactory.getInstance() 12 | .getStringProperty(Constants.DEPLOYMENT_APPLICATION_ID, Constants.APPLICATION_NAME); 13 | 14 | public HttpZuulFilterDaoBuilder() { 15 | 16 | } 17 | 18 | @Override 19 | public IZuulFilterDao build() { 20 | return new HttpZuulFilterDao(appName.get()); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/JDBCZuulFilterDaoBuilder.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import com.netflix.config.DynamicIntProperty; 4 | import com.netflix.config.DynamicLongProperty; 5 | import com.netflix.config.DynamicPropertyFactory; 6 | import com.netflix.config.DynamicStringProperty; 7 | import io.spring2go.zuul.common.Constants; 8 | import io.spring2go.zuul.common.IZuulFilterDao; 9 | import io.spring2go.zuul.common.IZuulFilterDaoBuilder; 10 | import com.zaxxer.hikari.HikariConfig; 11 | import com.zaxxer.hikari.HikariDataSource; 12 | 13 | public class JDBCZuulFilterDaoBuilder implements IZuulFilterDaoBuilder { 14 | private static final DynamicStringProperty dataSourceClass = DynamicPropertyFactory.getInstance() 15 | .getStringProperty(Constants.DATA_SOURCE_CLASS_NAME, null); 16 | private static final DynamicStringProperty url = DynamicPropertyFactory.getInstance() 17 | .getStringProperty(Constants.DATA_SOURCE_URL, null); 18 | private static final DynamicStringProperty user = DynamicPropertyFactory.getInstance() 19 | .getStringProperty(Constants.DATA_SOURCE_USER, null); 20 | private static final DynamicStringProperty password = DynamicPropertyFactory.getInstance() 21 | .getStringProperty(Constants.DATA_SOURCE_PASSWORD, null); 22 | private static final DynamicIntProperty minPoolSize = DynamicPropertyFactory.getInstance() 23 | .getIntProperty(Constants.DATA_SOURCE_MIN_POOL_SIZE, 10); 24 | private static final DynamicIntProperty maxPoolSize = DynamicPropertyFactory.getInstance() 25 | .getIntProperty(Constants.DATA_SOURCE_MAX_POOL_SIZE, 20); 26 | private static final DynamicLongProperty connectionTimeout = DynamicPropertyFactory.getInstance() 27 | .getLongProperty(Constants.DATA_SOURCE_CONNECT_TIMEOUT, 1000); 28 | private static final DynamicLongProperty idleTimeout = DynamicPropertyFactory.getInstance() 29 | .getLongProperty(Constants.DATA_SOURCE_IDLE_TIMEOUT, 600000); 30 | private static final DynamicLongProperty maxLifetime = DynamicPropertyFactory.getInstance() 31 | .getLongProperty(Constants.DATA_SOURCE_MAX_LIFETIME, 1800000); 32 | 33 | // private static final DynamicStringProperty environment = DynamicPropertyFactory.getInstance() 34 | // .getStringProperty(Constants.DEPLOY_ENVIRONMENT, "test"); 35 | 36 | private static final DynamicStringProperty filterTableName = DynamicPropertyFactory.getInstance() 37 | .getStringProperty(Constants.FILTER_TABLE_NAME, null); 38 | 39 | private static final DynamicStringProperty appName = DynamicPropertyFactory.getInstance() 40 | .getStringProperty(Constants.DEPLOYMENT_APPLICATION_ID, Constants.APPLICATION_NAME); 41 | 42 | private HikariDataSource dataSource; 43 | private String filterTable; 44 | 45 | public JDBCZuulFilterDaoBuilder() { 46 | HikariConfig config = new HikariConfig(); 47 | config.setDataSourceClassName(dataSourceClass.get()); 48 | config.addDataSourceProperty("url", url.get()); 49 | config.addDataSourceProperty("user", user.get()); 50 | config.addDataSourceProperty("password", password.get()); 51 | 52 | config.setMinimumPoolSize(minPoolSize.get()); 53 | config.setMaximumPoolSize(maxPoolSize.get()); 54 | config.setConnectionTimeout(connectionTimeout.get()); 55 | config.setIdleTimeout(idleTimeout.get()); 56 | config.setMaxLifetime(maxLifetime.get()); 57 | 58 | this.dataSource = new HikariDataSource(config); 59 | this.filterTable = filterTableName.get(); //+ "_" + environment.get(); 60 | } 61 | 62 | @Override 63 | public IZuulFilterDao build() { 64 | return new HystrixZuulFilterDao(new JDBCZuulFilterDao(filterTable, dataSource, appName.get())); 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/ZuulFilter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import com.netflix.config.DynamicBooleanProperty; 4 | import com.netflix.config.DynamicPropertyFactory; 5 | import io.spring2go.zuul.common.ExecutionStatus; 6 | import io.spring2go.zuul.common.ZuulFilterResult; 7 | import io.spring2go.zuul.common.IZuulFilter; 8 | import io.spring2go.zuul.context.RequestContext; 9 | 10 | /** 11 | * Base abstract class for ZuulFilters. The base class defines abstract methods 12 | * to define: filterType() - to classify a filter by type. Standard types in 13 | * Zuul Gateway are "pre" for pre-routing filtering, "route" for routing to an 14 | * origin, "post" for post-routing filters, "error" for error handling. We also 15 | * support a "static" type for static responses see StaticResponseFilter. Any 16 | * filterType made be created or added and run by calling 17 | * FilterProcessor.runFilters(type) 18 | *

19 | * filterOrder() must also be defined for a filter. Filters may have the same 20 | * filterOrder if precedence is not important for a filter. filterOrders do not 21 | * need to be sequential. 22 | *

23 | * ZuulFilters may be disabled using Archius Properties. 24 | *

25 | * By default ZuulFilters are static; they don't carry state. This may be 26 | * overridden by overriding the isStaticFilter() property to false 27 | * 28 | */ 29 | public abstract class ZuulFilter implements IZuulFilter, Comparable { 30 | 31 | private final DynamicBooleanProperty filterDisabled = DynamicPropertyFactory.getInstance() 32 | .getBooleanProperty(disablePropertyName(), false); 33 | 34 | /** 35 | * to classify a filter by type. Standard types in Zuul are "pre" for 36 | * pre-routing filtering, "route" for routing to an origin, "post" for 37 | * post-routing filters, "error" for error handling. We also support a 38 | * "static" type for static responses see StaticResponseFilter. Any 39 | * filterType made be created or added and run by calling 40 | * FilterProcessor.runFilters(type) 41 | * 42 | * @return A String representing that type 43 | */ 44 | abstract public String filterType(); 45 | 46 | /** 47 | * filterOrder() must also be defined for a filter. Filters may have the 48 | * same filterOrder if precedence is not important for a filter. 49 | * filterOrders do not need to be sequential. 50 | * 51 | * @return the int order of a filter 52 | */ 53 | abstract public int filterOrder(); 54 | 55 | /** 56 | * By default ZuulFilters are static; they don't carry state. This may be 57 | * overridden by overriding the isStaticFilter() property to false 58 | * 59 | * @return true by default 60 | */ 61 | public boolean isStaticFilter() { 62 | return true; 63 | } 64 | 65 | /** 66 | * The name of the Archaius property to disable this filter. by default it 67 | * is zuul.[classname].[filtertype].disable 68 | * 69 | * @return 70 | */ 71 | public String disablePropertyName() { 72 | return "zuul." + this.getClass().getSimpleName() + "." + filterType() + ".disable"; 73 | } 74 | 75 | /** 76 | * If true, the filter has been disabled by archaius and will not be run 77 | * 78 | * @return 79 | */ 80 | public boolean isFilterDisabled() { 81 | return filterDisabled.get(); 82 | } 83 | 84 | /** 85 | * runFilter checks !isFilterDisabled() and shouldFilter(). The run() method 86 | * is invoked if both are true. 87 | * 88 | * @return the return from ZuulFilterResult 89 | */ 90 | public ZuulFilterResult runFilter() { 91 | ZuulFilterResult tr = new ZuulFilterResult(); 92 | 93 | if (!filterDisabled.get()) { 94 | if (shouldFilter()) { 95 | try { 96 | Object res = run(); 97 | tr.setStatus(ExecutionStatus.SUCCESS); 98 | tr.setResult(res); 99 | } catch (Throwable t) { 100 | tr.setException(t); 101 | tr.setStatus(ExecutionStatus.FAILED); 102 | } 103 | } else { 104 | tr.setStatus(ExecutionStatus.SKIPPED); 105 | } 106 | } 107 | 108 | return tr; 109 | } 110 | 111 | public int compareTo(ZuulFilter filter) { 112 | return this.filterOrder() - filter.filterOrder(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/filters/ZuulFilterDaoFactory.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.filters; 2 | 3 | import java.util.concurrent.ConcurrentMap; 4 | 5 | import com.google.common.collect.Maps; 6 | import com.netflix.config.DynamicPropertyFactory; 7 | import com.netflix.config.DynamicStringProperty; 8 | import io.spring2go.zuul.common.Constants; 9 | import io.spring2go.zuul.common.IZuulFilterDao; 10 | 11 | public class ZuulFilterDaoFactory { 12 | private static final DynamicStringProperty daoType = DynamicPropertyFactory.getInstance().getStringProperty(Constants.ZUUL_FILTER_DAO_TYPE, "jdbc"); 13 | 14 | private static ConcurrentMap daoCache = Maps.newConcurrentMap(); 15 | 16 | private ZuulFilterDaoFactory(){ 17 | 18 | } 19 | 20 | public static IZuulFilterDao getZuulFilterDao(){ 21 | IZuulFilterDao dao = daoCache.get(daoType.get()); 22 | 23 | if(dao != null){ 24 | return dao; 25 | } 26 | 27 | if("jdbc".equalsIgnoreCase(daoType.get())){ 28 | dao = new JDBCZuulFilterDaoBuilder().build(); 29 | }else if("http".equalsIgnoreCase(daoType.get())){ 30 | dao = new HttpZuulFilterDaoBuilder().build(); 31 | }else{ 32 | dao = new JDBCZuulFilterDaoBuilder().build(); 33 | } 34 | 35 | daoCache.putIfAbsent(daoType.get(), dao); 36 | 37 | return dao; 38 | } 39 | 40 | public static String getCurrentType(){ 41 | return daoType.get(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/groovy/GroovyCompiler.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.groovy; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import io.spring2go.zuul.common.IDynamicCodeCompiler; 9 | import groovy.lang.GroovyClassLoader; 10 | 11 | /** 12 | * Groovy code compiler 13 | */ 14 | public class GroovyCompiler implements IDynamicCodeCompiler { 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(GroovyCompiler.class); 17 | 18 | /** 19 | * Compiles Groovy code and returns the Class of the compiles code. 20 | * 21 | * @param sCode 22 | * @param sName 23 | * @return 24 | */ 25 | public Class compile(String sCode, String sName) { 26 | GroovyClassLoader loader = getGroovyClassLoader(); 27 | LOGGER.warn("Compiling filter: " + sName); 28 | Class groovyClass = loader.parseClass(sCode, sName); 29 | return groovyClass; 30 | } 31 | 32 | /** 33 | * @return a new GroovyClassLoader 34 | */ 35 | GroovyClassLoader getGroovyClassLoader() { 36 | return new GroovyClassLoader(); 37 | } 38 | 39 | /** 40 | * Compiles groovy class from a file 41 | * 42 | * @param file 43 | * @return 44 | * @throws java.io.IOException 45 | */ 46 | public Class compile(File file) throws IOException { 47 | GroovyClassLoader loader = getGroovyClassLoader(); 48 | Class groovyClass = loader.parseClass(file); 49 | return groovyClass; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/groovy/GroovyFileFilter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.groovy; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | 6 | /** 7 | * Filters only .groovy files 8 | */ 9 | public class GroovyFileFilter implements FilenameFilter { 10 | public boolean accept(File dir, String name) { 11 | return name.endsWith(".groovy"); 12 | } 13 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/HttpClientResponse.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import java.io.InputStream; 4 | import java.net.URI; 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import com.google.common.collect.ArrayListMultimap; 10 | import com.google.common.collect.Multimap; 11 | import com.google.common.reflect.TypeToken; 12 | import com.netflix.client.ClientException; 13 | import com.netflix.client.http.HttpResponse; 14 | import com.sun.jersey.api.client.ClientResponse; 15 | import com.sun.jersey.api.client.UniformInterfaceException; 16 | 17 | /** 18 | * A NIWS Client Response 19 | * (this version just wraps Jersey Client response) 20 | * @author stonse 21 | * 22 | */ 23 | class HttpClientResponse implements HttpResponse { 24 | 25 | private ClientResponse bcr = null; 26 | 27 | private URI requestedURI; // the request url that got this response 28 | 29 | private Multimap headers = ArrayListMultimap.create(); 30 | 31 | public HttpClientResponse(ClientResponse cr){ 32 | bcr = cr; 33 | for (Map.Entry> entry: bcr.getHeaders().entrySet()) { 34 | if (entry.getKey() != null && entry.getValue() != null) { 35 | headers.putAll(entry.getKey(), entry.getValue()); 36 | } 37 | } 38 | } 39 | 40 | /** 41 | * Returns the raw entity if available from the response 42 | * @return 43 | * @throws IllegalArgumentException 44 | * @throws ClientException 45 | */ 46 | public InputStream getRawEntity() throws ClientException{ 47 | return bcr.getEntityInputStream(); 48 | } 49 | 50 | 51 | public T getEntity(Class c) throws Exception { 52 | T t = null; 53 | try { 54 | t = this.bcr.getEntity(c); 55 | } catch (UniformInterfaceException e) { 56 | throw new ClientException(ClientException.ErrorType.GENERAL, e.getMessage(), e.getCause()); 57 | } 58 | return t; 59 | } 60 | 61 | @Override 62 | public Map> getHeaders() { 63 | return headers.asMap(); 64 | } 65 | 66 | public int getStatus() { 67 | return bcr.getStatus(); 68 | } 69 | 70 | @Override 71 | public boolean isSuccess() { 72 | boolean isSuccess = false; 73 | ClientResponse.Status s = bcr != null? bcr.getClientResponseStatus(): null; 74 | isSuccess = s!=null? (s.getFamily() == javax.ws.rs.core.Response.Status.Family.SUCCESSFUL): false; 75 | return isSuccess; 76 | } 77 | 78 | public boolean hasEntity() { 79 | return bcr.hasEntity(); 80 | } 81 | 82 | @Override 83 | public URI getRequestedURI() { 84 | return this.requestedURI; 85 | } 86 | 87 | public void setRequestedURI(URI requestedURI) { 88 | this.requestedURI = requestedURI; 89 | } 90 | 91 | @Override 92 | public Object getPayload() throws ClientException { 93 | if (hasEntity()) { 94 | return getRawEntity(); 95 | } else { 96 | return null; 97 | } 98 | } 99 | 100 | @Override 101 | public boolean hasPayload() { 102 | return hasEntity(); 103 | } 104 | 105 | public ClientResponse getJerseyClientResponse() { 106 | return bcr; 107 | } 108 | 109 | @Override 110 | public void close() { 111 | bcr.close(); 112 | } 113 | 114 | @SuppressWarnings("unchecked") 115 | @Override 116 | public T getEntity(TypeToken type) throws Exception { 117 | return (T) getEntity(type.getRawType()); 118 | } 119 | 120 | @Override 121 | public InputStream getInputStream() throws ClientException { 122 | return getRawEntity(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/RestClientFactory.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import java.util.concurrent.ConcurrentMap; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.google.common.collect.Maps; 9 | import com.netflix.client.AbstractLoadBalancerAwareClient; 10 | import com.netflix.client.ClientException; 11 | import com.netflix.client.ClientFactory; 12 | import com.netflix.client.config.CommonClientConfigKey; 13 | import com.netflix.client.config.DefaultClientConfigImpl; 14 | import com.netflix.client.config.IClientConfig; 15 | import com.netflix.loadbalancer.ILoadBalancer; 16 | import io.spring2go.zuul.util.SleepUtil; 17 | 18 | public class RestClientFactory { 19 | private static Logger logger = LoggerFactory.getLogger(RestClientFactory.class); 20 | 21 | private static final ConcurrentMap restClientMap = Maps.newConcurrentMap(); 22 | 23 | public static RestClient getRestClient(String serviceName,IClientConfig clientConfig) throws ClientException{ 24 | RestClient oldClient = restClientMap.get(serviceName); 25 | 26 | if(oldClient == null){ 27 | synchronized (RestClient.class) { 28 | oldClient = restClientMap.get(serviceName); 29 | if(oldClient == null){ 30 | RestClient client = newRestClient(serviceName,clientConfig); 31 | oldClient = restClientMap.putIfAbsent(serviceName, client); 32 | 33 | if(oldClient != null){ 34 | oldClient.shutdown(); 35 | } 36 | oldClient = client; 37 | } 38 | } 39 | } 40 | 41 | return oldClient; 42 | } 43 | 44 | public static void closeRestClient(String serviceName){ 45 | RestClient oldClient = restClientMap.remove(serviceName); 46 | if(oldClient != null){ 47 | SleepUtil.sleep(30*1000); 48 | oldClient.shutdown(); 49 | } 50 | } 51 | 52 | 53 | private static RestClient newRestClient(String restClientName,IClientConfig clientConfig) throws ClientException{ 54 | RestClient restClient = new RestClient(clientConfig); 55 | ILoadBalancer loadBalancer = null; 56 | boolean initializeNFLoadBalancer = Boolean.parseBoolean(clientConfig.getProperty( 57 | CommonClientConfigKey.InitializeNFLoadBalancer, DefaultClientConfigImpl.DEFAULT_ENABLE_LOADBALANCER).toString()); 58 | if (initializeNFLoadBalancer) { 59 | loadBalancer = newLoadBalancerFromConfig(restClientName, clientConfig); 60 | } 61 | if (restClient instanceof AbstractLoadBalancerAwareClient) { 62 | ((AbstractLoadBalancerAwareClient) restClient).setLoadBalancer(loadBalancer); 63 | } 64 | return restClient; 65 | } 66 | 67 | private static ILoadBalancer newLoadBalancerFromConfig(String restClientName,IClientConfig clientConfig) throws ClientException { 68 | ILoadBalancer lb = null; 69 | try { 70 | String loadBalancerClassName = (String) clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerClassName); 71 | lb = (ILoadBalancer) ClientFactory.instantiateInstanceWithClientConfig(loadBalancerClassName, clientConfig); 72 | 73 | logger.info("Client:" + restClientName + " instantiated a LoadBalancer:" + lb.toString()); 74 | return lb; 75 | } catch (Exception e) { 76 | throw new ClientException("Unable to instantiate/associate LoadBalancer with Client:" + restClientName, e); 77 | } 78 | } 79 | 80 | } 81 | 82 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/RibbonRequestCommandForSemaphoreIsolation.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import com.netflix.client.AbstractLoadBalancerAwareClient; 4 | import com.netflix.client.http.HttpRequest; 5 | import com.netflix.hystrix.HystrixCommandGroupKey; 6 | import com.netflix.hystrix.HystrixCommandKey; 7 | import com.netflix.hystrix.HystrixCommandProperties; 8 | 9 | public class RibbonRequestCommandForSemaphoreIsolation extends RibbonZuulCommon { 10 | 11 | 12 | 13 | public RibbonRequestCommandForSemaphoreIsolation(AbstractLoadBalancerAwareClient client,HttpRequest request, String serviceName, String commandGroup, 14 | String commandKey) { 15 | super(client,request, serviceName, commandGroup, commandKey, 16 | Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(commandGroup)) 17 | .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)) 18 | .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy( 19 | HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/RibbonRequestCommandForThreadIsolation.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import com.netflix.client.AbstractLoadBalancerAwareClient; 4 | import com.netflix.client.http.HttpRequest; 5 | import com.netflix.hystrix.HystrixCommandGroupKey; 6 | import com.netflix.hystrix.HystrixCommandKey; 7 | import com.netflix.hystrix.HystrixCommandProperties; 8 | import com.netflix.hystrix.HystrixThreadPoolKey; 9 | 10 | public class RibbonRequestCommandForThreadIsolation extends RibbonZuulCommon { 11 | 12 | public RibbonRequestCommandForThreadIsolation(AbstractLoadBalancerAwareClient client,HttpRequest request, String serviceName, String commandGroup, 13 | String commandKey, String threadPoolKey) { 14 | super(client,request, serviceName, commandGroup, commandKey, 15 | Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(commandGroup)) 16 | .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)) 17 | .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey)) 18 | .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy( 19 | HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))); 20 | 21 | } 22 | 23 | public RibbonRequestCommandForThreadIsolation(AbstractLoadBalancerAwareClient client,HttpRequest request, String serviceName, String commandGroup, 24 | String commandKey) { 25 | this(client,request, serviceName, commandGroup, 26 | commandKey, ZuulCommandHelper.getThreadPoolKey(commandGroup,commandKey)); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/RibbonZuulCommon.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import java.util.List; 4 | 5 | import javax.servlet.http.HttpServletResponse; 6 | 7 | import com.google.common.collect.Lists; 8 | import com.netflix.appinfo.InstanceInfo; 9 | import com.netflix.appinfo.InstanceInfo.InstanceStatus; 10 | import com.netflix.client.AbstractLoadBalancerAwareClient; 11 | import com.netflix.client.ClientFactory; 12 | import com.netflix.client.http.HttpRequest; 13 | import com.netflix.client.http.HttpResponse; 14 | import com.netflix.discovery.DiscoveryManager; 15 | import com.netflix.discovery.shared.Application; 16 | import com.netflix.hystrix.HystrixCommand; 17 | import com.netflix.loadbalancer.ZoneAwareLoadBalancer; 18 | 19 | import com.netflix.niws.loadbalancer.DiscoveryEnabledServer; 20 | import io.spring2go.zuul.common.ZuulException; 21 | 22 | public abstract class RibbonZuulCommon extends HystrixCommand { 23 | 24 | protected String commandGroup; 25 | protected String commandKey; 26 | protected String serviceName; 27 | protected HttpRequest request; 28 | protected AbstractLoadBalancerAwareClient client; 29 | 30 | public RibbonZuulCommon(AbstractLoadBalancerAwareClient client,HttpRequest request,String serviceName, String commandGroup, String commandKey,Setter setter) { 31 | super(setter); 32 | this.commandKey = commandKey; 33 | this.commandGroup = commandGroup; 34 | this.serviceName = serviceName; 35 | this.request = request; 36 | this.client = client; 37 | } 38 | 39 | protected RestClient getRestClient() throws ZuulException { 40 | Application application = DiscoveryManager.getInstance().getDiscoveryClient().getApplication(serviceName); 41 | if (application == null) { 42 | throw new ZuulException( "Service-NotFoud",HttpServletResponse.SC_NOT_FOUND, serviceName + "服务未找到"); 43 | } 44 | 45 | List instances = Lists.newArrayList(); 46 | for (InstanceInfo info : application.getInstances()) { 47 | if (info.getStatus() == InstanceStatus.UP) { 48 | instances.add(new DiscoveryEnabledServer(info, false, false)); 49 | } 50 | } 51 | 52 | RestClient client = (RestClient) ClientFactory.getNamedClient(serviceName); 53 | ZoneAwareLoadBalancer loadbalancer = (ZoneAwareLoadBalancer) client.getLoadBalancer(); 54 | 55 | // //loadbalancer.setServersList(instances); 56 | // IRule rule = new RandomRule(); 57 | // int ruleLoad = ZuulCommandHelper.getLoadBalanceRule(commandGroup, commandKey); 58 | // if (ruleLoad == 2) { 59 | // rule = new ClientConfigEnabledRoundRobinRule(); 60 | // } else if (ruleLoad == 3) { 61 | // rule=new AvailabilityFilteringRule(); 62 | // } else if (ruleLoad == 3) { 63 | // rule=new ZoneAvoidanceRule(); 64 | // } else if (ruleLoad == 4) { 65 | // rule=new RetryRule(); 66 | // } else if (ruleLoad == 5) { 67 | // rule=new RoundRobinRule(); 68 | // }else if (ruleLoad == 6) { 69 | // rule=new ResponseTimeWeightedRule(); 70 | // }else if (ruleLoad == 7) { 71 | // rule=new WeightedResponseTimeRule(); 72 | // } 73 | // loadbalancer.setRule(rule); 74 | // client.setLoadBalancer(loadbalancer); 75 | return client; 76 | } 77 | 78 | @Override 79 | protected HttpResponse run() throws Exception { 80 | 81 | HttpResponse response = (HttpResponse) client.executeWithLoadBalancer(request); 82 | return response; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/ZuulRequestCommandForSemaphoreIsolation.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import com.dianping.cat.Cat; 4 | import com.dianping.cat.Cat.Context; 5 | import com.dianping.cat.CatConstants; 6 | import com.dianping.cat.message.Message; 7 | import com.dianping.cat.message.Transaction; 8 | import com.netflix.hystrix.HystrixCommand; 9 | import com.netflix.hystrix.HystrixCommandGroupKey; 10 | import com.netflix.hystrix.HystrixCommandKey; 11 | import com.netflix.hystrix.HystrixCommandProperties; 12 | import io.spring2go.zuul.common.CatContext; 13 | import io.spring2go.zuul.common.Constants; 14 | 15 | import org.apache.http.HttpResponse; 16 | import org.apache.http.client.HttpClient; 17 | import org.apache.http.client.methods.HttpUriRequest; 18 | import org.apache.http.protocol.HttpContext; 19 | 20 | import java.io.IOException; 21 | 22 | public class ZuulRequestCommandForSemaphoreIsolation extends HystrixCommand { 23 | 24 | HttpClient httpclient; 25 | HttpUriRequest httpUriRequest; 26 | HttpContext httpContext; 27 | 28 | public ZuulRequestCommandForSemaphoreIsolation(HttpClient httpclient, HttpUriRequest httpUriRequest, String commandGroup, String commandKey) { 29 | this(httpclient, httpUriRequest, null, commandGroup, commandKey); 30 | } 31 | 32 | public ZuulRequestCommandForSemaphoreIsolation(HttpClient httpclient, HttpUriRequest httpUriRequest, HttpContext httpContext, String commandGroup, String commandKey) { 33 | super(Setter 34 | .withGroupKey(HystrixCommandGroupKey.Factory.asKey(commandGroup)) 35 | .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)) 36 | .andCommandPropertiesDefaults( 37 | // we want to default to semaphore-isolation since this wraps 38 | // 2 others commands that are already thread isolated 39 | HystrixCommandProperties.Setter() 40 | .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE) 41 | )); 42 | 43 | this.httpclient = httpclient; 44 | this.httpUriRequest = httpUriRequest; 45 | this.httpContext = httpContext; 46 | } 47 | 48 | @Override 49 | protected HttpResponse run() throws Exception { 50 | 51 | Transaction t = Cat.newTransaction(CatConstants.TYPE_REMOTE_CALL, httpUriRequest.getURI().toString()); 52 | 53 | try { 54 | HttpResponse response = forward(); 55 | t.setStatus(Transaction.SUCCESS); 56 | return response; 57 | } catch (IOException e) { 58 | t.setStatus(e); 59 | Cat.logError(e); 60 | throw e; 61 | } finally { 62 | t.complete(); 63 | } 64 | } 65 | 66 | HttpResponse forward() throws IOException { 67 | 68 | Context ctx = new CatContext(); 69 | Cat.logRemoteCallClient(ctx); 70 | httpUriRequest.addHeader(Constants.CAT_ROOT_MESSAGE_ID, ctx.getProperty(Cat.Context.ROOT)); 71 | httpUriRequest.addHeader(Constants.CAT_PARENT_MESSAGE_ID, ctx.getProperty(Cat.Context.PARENT)); 72 | httpUriRequest.addHeader(Constants.CAT_CHILD_MESSAGE_ID, ctx.getProperty(Cat.Context.CHILD)); 73 | return httpclient.execute(httpUriRequest, httpContext); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/hystrix/ZuulRequestCommandForThreadIsolation.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.hystrix; 2 | 3 | import java.io.IOException; 4 | 5 | import org.apache.http.HttpResponse; 6 | import org.apache.http.client.HttpClient; 7 | import org.apache.http.client.methods.HttpUriRequest; 8 | import org.apache.http.protocol.HttpContext; 9 | 10 | import com.dianping.cat.Cat; 11 | import com.dianping.cat.Cat.Context; 12 | import com.netflix.hystrix.HystrixCommand; 13 | import com.netflix.hystrix.HystrixCommandGroupKey; 14 | import com.netflix.hystrix.HystrixCommandKey; 15 | import com.netflix.hystrix.HystrixCommandProperties; 16 | import com.netflix.hystrix.HystrixThreadPoolKey; 17 | import io.spring2go.zuul.common.CatContext; 18 | import io.spring2go.zuul.common.Constants; 19 | 20 | public class ZuulRequestCommandForThreadIsolation extends HystrixCommand { 21 | 22 | HttpClient httpclient; 23 | HttpUriRequest httpUriRequest; 24 | HttpContext httpContext; 25 | 26 | public ZuulRequestCommandForThreadIsolation(HttpClient httpclient, HttpUriRequest httpUriRequest, String commandGroup, String commandKey) { 27 | this(httpclient, httpUriRequest, null,commandGroup, commandKey); 28 | } 29 | public ZuulRequestCommandForThreadIsolation(HttpClient httpclient, HttpUriRequest httpUriRequest, HttpContext httpContext, String commandGroup, String commandKey) { 30 | this(httpclient, httpUriRequest, httpContext,commandGroup, commandKey, ZuulCommandHelper.getThreadPoolKey(commandGroup,commandKey)); 31 | } 32 | 33 | public ZuulRequestCommandForThreadIsolation(HttpClient httpclient, HttpUriRequest httpUriRequest, HttpContext httpContext, String commandGroup, String commandKey, String threadPoolKey) { 34 | 35 | super(Setter 36 | .withGroupKey(HystrixCommandGroupKey.Factory.asKey(commandGroup)) 37 | .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)) 38 | .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey)) 39 | .andCommandPropertiesDefaults( 40 | HystrixCommandProperties.Setter() 41 | .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD) 42 | ) 43 | ); 44 | this.httpclient = httpclient; 45 | this.httpUriRequest = httpUriRequest; 46 | this.httpContext = httpContext; 47 | } 48 | 49 | @Override 50 | protected HttpResponse run() throws Exception { 51 | try { 52 | return forward(); 53 | } catch (IOException e) { 54 | throw e; 55 | } 56 | } 57 | 58 | HttpResponse forward() throws IOException { 59 | Context ctx = new CatContext(); 60 | Cat.logRemoteCallClient(ctx); 61 | httpUriRequest.addHeader(Constants.CAT_ROOT_MESSAGE_ID, ctx.getProperty(Cat.Context.ROOT)); 62 | httpUriRequest.addHeader(Constants.CAT_PARENT_MESSAGE_ID, ctx.getProperty(Cat.Context.PARENT)); 63 | httpUriRequest.addHeader(Constants.CAT_CHILD_MESSAGE_ID, ctx.getProperty(Cat.Context.CHILD)); 64 | return httpclient.execute(httpUriRequest, httpContext); 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/DebugHeader.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import java.util.List; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import com.netflix.config.DynamicBooleanProperty; 9 | import com.netflix.config.DynamicPropertyFactory; 10 | import com.netflix.util.Pair; 11 | import io.spring2go.zuul.context.RequestContext; 12 | import io.spring2go.zuul.filters.ZuulFilter; 13 | 14 | public class DebugHeader extends ZuulFilter { 15 | static final DynamicBooleanProperty INCLUDE_DEBUG_HEADER = 16 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.include.debug.header", true); 17 | 18 | static final DynamicBooleanProperty INCLUDE_ROUTE_URL_HEADER = 19 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.include-route-url-header", false); 20 | 21 | @Override 22 | public String filterType() { 23 | return "post"; 24 | } 25 | 26 | @Override 27 | public int filterOrder() { 28 | return 10; 29 | } 30 | 31 | @Override 32 | public boolean shouldFilter() { 33 | //request was routed to a zuul gateway server, so don't send response headers 34 | return INCLUDE_DEBUG_HEADER.get(); 35 | } 36 | 37 | @Override 38 | public Object run() { 39 | addStandardResponseHeaders(RequestContext.getCurrentContext().getRequest(), RequestContext.getCurrentContext().getResponse()); 40 | return null; 41 | } 42 | 43 | public void addStandardResponseHeaders(HttpServletRequest req, HttpServletResponse res) { 44 | 45 | RequestContext context = RequestContext.getCurrentContext(); 46 | List> headers = context.getZuulResponseHeaders(); 47 | headers.add(new Pair("X_ZUUL", "mobile_gateway")); 48 | // TODO, get zuul instance id 49 | headers.add(new Pair("X_ZUUL_INSTANCE", "unknown")); 50 | headers.add(new Pair("CONNECTION", "KEEP_ALIVE")); 51 | headers.add(new Pair("X_ZUUL_FILTER_EXECUTION_STATUS", context.getFilterExecutionSummary().toString())); 52 | headers.add(new Pair("X_ORIGINATING_URL", getOriginatingURL())); 53 | if (INCLUDE_ROUTE_URL_HEADER.get()) { 54 | String routeUrl = context.getRouteUrl().toString(); 55 | if (routeUrl != null && !routeUrl.isEmpty()) { 56 | headers.add(new Pair("x-zuul-route-url", routeUrl)); 57 | } 58 | } 59 | 60 | //Support CROS 61 | headers.add(new Pair("Access-Control-Allow-Origin", "*")); 62 | headers.add(new Pair("Access-Control-Allow-Headers","Content-Type, Accept")); 63 | 64 | headers.add(new Pair("x-zuul-remote-call-cost", String.valueOf(RequestContext.getCurrentContext().get("remoteCallCost")))); 65 | 66 | if (!context.errorHandled() && context.getResponseStatusCode() >= 400) { 67 | headers.add(new Pair("X_ZUUL_ERROR_CAUSE", "Error from Origin")); 68 | 69 | } 70 | 71 | 72 | } 73 | 74 | String getOriginatingURL() { 75 | HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); 76 | 77 | String protocol = request.getHeader("X_FORWARDED_PROTO"); 78 | if (protocol == null) protocol = "http"; 79 | String host = request.getHeader("HOST"); 80 | String uri = request.getRequestURI(); 81 | String URL = "${protocol}://${host}${uri}"; 82 | if (request.getQueryString() != null) { 83 | URL += "?${request.getQueryString()}"; 84 | } 85 | return URL; 86 | } 87 | 88 | 89 | } 90 | 91 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/DebugModeSetter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import com.netflix.config.DynamicBooleanProperty; 4 | import com.netflix.config.DynamicPropertyFactory; 5 | import com.netflix.config.DynamicStringProperty; 6 | import io.spring2go.zuul.common.Constants; 7 | import io.spring2go.zuul.context.RequestContext; 8 | import io.spring2go.zuul.filters.ZuulFilter; 9 | 10 | public class DebugModeSetter extends ZuulFilter { 11 | 12 | static final DynamicBooleanProperty couldSetDebug = 13 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.could.set.debug", true); 14 | static final DynamicBooleanProperty debugRequest = 15 | DynamicPropertyFactory.getInstance().getBooleanProperty(Constants.ZUUL_DEBUG_REQUEST, true); 16 | static final DynamicStringProperty debugParameter = 17 | DynamicPropertyFactory.getInstance().getStringProperty(Constants.ZUUL_DEBUG_PARAMETER, "debugRequest"); 18 | 19 | @Override 20 | public String filterType() { 21 | return "pre"; 22 | } 23 | 24 | @Override 25 | public int filterOrder() { 26 | return -100; 27 | } 28 | 29 | public boolean shouldFilter() { 30 | if (!couldSetDebug.get()) { 31 | return false; 32 | } 33 | System.out.println(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get())); 34 | if ("true".equals(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get()))) { 35 | 36 | return true; 37 | } 38 | return debugRequest.get(); 39 | } 40 | 41 | public Object run() { 42 | RequestContext.getCurrentContext().setDebugRequest(true); 43 | RequestContext.getCurrentContext().setDebugRouting(true); 44 | return null; 45 | } 46 | } 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/DebugRequest.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import java.util.Enumeration; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | import com.netflix.config.DynamicBooleanProperty; 8 | import com.netflix.config.DynamicPropertyFactory; 9 | import io.spring2go.zuul.context.RequestContext; 10 | import io.spring2go.zuul.filters.ZuulFilter; 11 | import io.spring2go.zuul.util.Debug; 12 | 13 | public class DebugRequest extends ZuulFilter { 14 | private static final String ZUUL_BODY_DEBUG_DISABLE = "zuul.body.debug.disable"; 15 | private static final String ZUUL_HEADER_DEBUG_DISABLE = "zuul.header.debug.disable"; 16 | static final DynamicBooleanProperty BODY_DEBUG_DISABLED = 17 | DynamicPropertyFactory.getInstance().getBooleanProperty(ZUUL_BODY_DEBUG_DISABLE, false); 18 | static final DynamicBooleanProperty HEADER_DEBUG_DISABLED = 19 | DynamicPropertyFactory.getInstance().getBooleanProperty(ZUUL_HEADER_DEBUG_DISABLE, true); 20 | 21 | @Override 22 | public String filterType() { 23 | return "pre"; 24 | } 25 | 26 | @Override 27 | public int filterOrder() { 28 | return -10; 29 | } 30 | 31 | @Override 32 | public boolean shouldFilter() { 33 | return Debug.debugRequest(); 34 | } 35 | 36 | @Override 37 | public Object run() { 38 | HttpServletRequest req = RequestContext.getCurrentContext().getRequest(); 39 | 40 | Debug.addRequestDebug("REQUEST:: " + req.getScheme() + " " + req.getRemoteAddr() + ":" + req.getRemotePort()); 41 | Debug.addRequestDebug("REQUEST:: > " + req.getMethod() + " " + req.getRequestURI() + " " + req.getProtocol()); 42 | 43 | Enumeration headerIt = req.getHeaderNames(); 44 | while (headerIt.hasMoreElements()) { 45 | String name = (String) headerIt.nextElement(); 46 | String value = req.getHeader(name); 47 | Debug.addRequestDebug("REQUEST:: > " + name + ":" + value); 48 | } 49 | 50 | // final RequestContext ctx = RequestContext.getCurrentContext(); 51 | // if (!ctx.isChunkedRequestBody() && !BODY_DEBUG_DISABLED.get()) { 52 | // InputStream inp = ctx.getRequest().getInputStream(); 53 | // String body = null; 54 | // if (inp != null) { 55 | // body = inp.getText(); 56 | // Debug.addRequestDebug("REQUEST:: > " + body); 57 | // } 58 | // } 59 | return null; 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/DebugResponse.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import java.util.List; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.netflix.config.DynamicBooleanProperty; 9 | import com.netflix.config.DynamicPropertyFactory; 10 | import com.netflix.util.Pair; 11 | import io.spring2go.zuul.context.RequestContext; 12 | import io.spring2go.zuul.filters.ZuulFilter; 13 | import io.spring2go.zuul.util.Debug; 14 | 15 | public class DebugResponse extends ZuulFilter { 16 | private static final Logger LOGGER = LoggerFactory.getLogger(DebugResponse.class); 17 | private static final String ZUUL_BODY_DEBUG_DISABLE = "zuul.body.debug.disable"; 18 | private static final String ZUUL_HEADER_DEBUG_DISABLE = "zuul.header.debug.disable"; 19 | static final DynamicBooleanProperty BODY_DEBUG_DISABLED = 20 | DynamicPropertyFactory.getInstance().getBooleanProperty(ZUUL_BODY_DEBUG_DISABLE, false); 21 | static final DynamicBooleanProperty HEADER_DEBUG_DISABLED = 22 | DynamicPropertyFactory.getInstance().getBooleanProperty(ZUUL_HEADER_DEBUG_DISABLE, true); 23 | 24 | @Override 25 | public String filterType() { 26 | return "post"; 27 | } 28 | 29 | @Override 30 | public int filterOrder() { 31 | return 1000; 32 | } 33 | 34 | @Override 35 | public boolean shouldFilter() { 36 | return Debug.debugRequest(); 37 | } 38 | 39 | @Override 40 | public Object run() { 41 | List> headers = RequestContext.getCurrentContext().getZuulResponseHeaders(); 42 | for (Pair it : headers) { 43 | Debug.addRequestDebug("OUTBOUND: < " + it.first() + ":" + it.second()); 44 | } 45 | List> headers1 = RequestContext.getCurrentContext().getOriginResponseHeaders(); 46 | for (Pair it : headers1) { 47 | Debug.addRequestDebug("OUTBOUND: < " + it.first() + ":" + it.second()); 48 | } 49 | dumpRoutingDebug(); 50 | dumpRequestDebug(); 51 | return null; 52 | } 53 | 54 | public void dumpRequestDebug() { 55 | @SuppressWarnings("unchecked") 56 | List rd = (List) RequestContext.getCurrentContext().get("requestDebug"); 57 | if(rd != null){ 58 | StringBuilder b = new StringBuilder(""); 59 | for (String it : rd) { 60 | b.append("REQUEST_DEBUG::"+it+"\n"); 61 | } 62 | LOGGER.info(b.toString()); 63 | } 64 | } 65 | 66 | public void dumpRoutingDebug() { 67 | @SuppressWarnings("unchecked") 68 | List rd = (List) RequestContext.getCurrentContext().get("routingDebug"); 69 | if(rd != null){ 70 | StringBuilder b = new StringBuilder(""); 71 | for (String it : rd) { 72 | b.append("ZUUL_DEBUG::"+it+"\n"); 73 | } 74 | LOGGER.info(b.toString()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import java.util.Enumeration; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import io.spring2go.zuul.common.ZuulException; 9 | import io.spring2go.zuul.common.ZuulHeaders; 10 | import io.spring2go.zuul.context.RequestContext; 11 | import io.spring2go.zuul.filters.ZuulFilter; 12 | 13 | /** 14 | * Generate a error response while there is an error. 15 | */ 16 | public class ErrorResponse extends ZuulFilter { 17 | private static final Logger logger = LoggerFactory.getLogger(ErrorResponse.class); 18 | 19 | @Override 20 | public String filterType() { 21 | return "error"; 22 | } 23 | 24 | @Override 25 | public int filterOrder() { 26 | return 10; 27 | } 28 | 29 | @Override 30 | public boolean shouldFilter() { 31 | RequestContext context = RequestContext.getCurrentContext(); 32 | return context.getThrowable() != null && !context.errorHandled(); 33 | } 34 | 35 | 36 | @SuppressWarnings("finally") 37 | @Override 38 | public Object run() { 39 | RequestContext ctx = RequestContext.getCurrentContext(); 40 | Throwable ex = ctx.getThrowable(); 41 | try { 42 | String errorCause="Zuul-Error-Unknown-Cause"; 43 | int responseStatusCode; 44 | 45 | if (ex instanceof ZuulException) { 46 | ZuulException exception=(ZuulException)ex; 47 | String cause = exception.errorCause; 48 | if(cause!=null) errorCause = cause; 49 | responseStatusCode = exception.nStatusCode; 50 | 51 | Enumeration headerIt = ctx.getRequest().getHeaderNames(); 52 | StringBuilder sb = new StringBuilder(ctx.getRequest().getRequestURI()+":"+errorCause); 53 | while (headerIt.hasMoreElements()) { 54 | String name = (String) headerIt.nextElement(); 55 | String value = ctx.getRequest().getHeader(name); 56 | sb.append("REQUEST:: > " + name + ":" + value+"\n"); 57 | } 58 | logger.error(sb.toString()); 59 | }else{ 60 | responseStatusCode = 500; 61 | } 62 | 63 | ctx.getResponse().addHeader(ZuulHeaders.X_ZUUL_ERROR_CAUSE, errorCause); 64 | 65 | Enumeration headerIt = ctx.getRequest().getHeaderNames(); 66 | StringBuilder sb = new StringBuilder(); 67 | while (headerIt.hasMoreElements()) { 68 | String name = (String) headerIt.nextElement(); 69 | String value = ctx.getRequest().getHeader(name); 70 | sb.append("REQUEST:: > " + name + ":" + value+"\n"); 71 | } 72 | logger.error(sb.toString()); 73 | 74 | if (getOverrideStatusCode()) { 75 | ctx.setResponseStatusCode(200); 76 | } else { 77 | ctx.setResponseStatusCode(responseStatusCode); 78 | } 79 | 80 | ctx.setSendZuulResponse(false); 81 | ctx.setResponseBody("Message\":\""+errorCause+"\"}"); 82 | } finally { 83 | ctx.setErrorHandled(true); //ErrorResponse was handled 84 | return null; 85 | } 86 | } 87 | 88 | private boolean getOverrideStatusCode() { 89 | String override = RequestContext.getCurrentContext().getRequest().getParameter("override_error_status"); 90 | if (getCallback() != null) return true; 91 | if (override == null) return false; 92 | return Boolean.valueOf(override); 93 | 94 | } 95 | 96 | private String getCallback() { 97 | String callback = RequestContext.getCurrentContext().getRequest().getParameter("callback"); 98 | if (callback == null) return null; 99 | return callback; 100 | } 101 | 102 | private String getOutputType() { 103 | String output = RequestContext.getCurrentContext().getRequest().getParameter("output"); 104 | if (output == null) return "json"; 105 | return output; 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/HealthCheck.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import javax.servlet.http.HttpServletResponse; 4 | 5 | import io.spring2go.zuul.context.RequestContext; 6 | import io.spring2go.zuul.filters.ZuulFilter; 7 | 8 | public class HealthCheck extends ZuulFilter{ 9 | 10 | @Override 11 | public String filterType() { 12 | return "pre"; 13 | } 14 | 15 | public String uri() { 16 | return "/healthcheck"; 17 | } 18 | 19 | @Override 20 | public boolean shouldFilter() { 21 | String path = RequestContext.getCurrentContext().getRequest().getRequestURI(); 22 | return path.equalsIgnoreCase(uri()); 23 | } 24 | 25 | public int filterOrder(){ 26 | return 0; 27 | } 28 | 29 | public String responseBody() { 30 | return "ok"; 31 | } 32 | 33 | @Override 34 | public Object run() { 35 | RequestContext ctx = RequestContext.getCurrentContext(); 36 | // Set the default response code for static filters to be 200 37 | ctx.getResponse().setStatus(HttpServletResponse.SC_OK); 38 | ctx.getResponse().setContentType("application/xml"); 39 | // first StaticResponseFilter instance to match wins, others do not set body and/or status 40 | if (ctx.getResponseBody() == null) { 41 | ctx.setResponseBody(responseBody()); 42 | ctx.setSendZuulResponse(false); 43 | } 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/MobileAddTimeStamp.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import io.spring2go.zuul.common.ZuulException; 4 | import io.spring2go.zuul.context.RequestContext; 5 | import io.spring2go.zuul.filters.ZuulFilter; 6 | 7 | public class MobileAddTimeStamp extends ZuulFilter { 8 | 9 | private final static int TIMESTAMP_EXPIRED_SECS = 600; 10 | 11 | @Override 12 | public String filterType() { 13 | return "post"; 14 | } 15 | 16 | @Override 17 | public boolean shouldFilter() { 18 | return true; 19 | } 20 | @Override 21 | public int filterOrder() { 22 | return 30; 23 | 24 | } 25 | @Override 26 | public Object run() throws ZuulException { 27 | RequestContext.getCurrentContext().addZuulResponseHeader("X-S2G-TIMESTAMP", String.valueOf(System.currentTimeMillis()/1000)); 28 | return true; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/Stats.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import io.spring2go.zuul.context.RequestContext; 4 | import io.spring2go.zuul.filters.ZuulFilter; 5 | import io.spring2go.zuul.monitoring.StatManager; 6 | 7 | public class Stats extends ZuulFilter { 8 | @Override 9 | public String filterType() { 10 | return "post"; 11 | } 12 | 13 | @Override 14 | public int filterOrder() { 15 | return 20000; 16 | } 17 | 18 | @Override 19 | public boolean shouldFilter() { 20 | return true; 21 | } 22 | 23 | @Override 24 | public Object run() { 25 | RequestContext ctx = RequestContext.getCurrentContext(); 26 | int status = ctx.getResponseStatusCode(); 27 | StatManager sm = StatManager.getManager(); 28 | sm.collectRequestStats(ctx.getRequest()); 29 | sm.collectRouteStatusStats(ctx.getRouteName(), status); 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/mobile/TestRouting.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | import java.util.HashMap; 6 | import java.util.concurrent.atomic.AtomicReference; 7 | 8 | import org.apache.commons.lang.StringUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import com.netflix.config.DynamicPropertyFactory; 13 | import com.netflix.config.DynamicStringProperty; 14 | 15 | import io.spring2go.zuul.common.ZuulException; 16 | import io.spring2go.zuul.context.RequestContext; 17 | import io.spring2go.zuul.filters.ZuulFilter; 18 | 19 | public class TestRouting extends ZuulFilter { 20 | 21 | private static Logger logger = LoggerFactory.getLogger(TestRouting.class); 22 | 23 | private static final AtomicReference> routingTableRef = new AtomicReference>(); 24 | 25 | private static final DynamicStringProperty ROUTING_TABLE_STRING_PROPERTY = DynamicPropertyFactory.getInstance() 26 | .getStringProperty("zuul.routing_table_string", null); 27 | 28 | static { 29 | buildRoutingTable(); 30 | 31 | ROUTING_TABLE_STRING_PROPERTY.addCallback(new Runnable() { 32 | 33 | @Override 34 | public void run() { 35 | buildRoutingTable(); 36 | } 37 | 38 | }); 39 | } 40 | 41 | static void buildRoutingTable() { 42 | logger.info("building routing table"); 43 | HashMap routingTable = new HashMap(); 44 | String routingTableString = ROUTING_TABLE_STRING_PROPERTY.get(); 45 | if (StringUtils.isEmpty(routingTableString)) { 46 | logger.warn("routing table string is empty, nothing to build"); 47 | return; 48 | } 49 | String[] routingEntries = routingTableString.split("&"); 50 | for (String routingEntry : routingEntries) { 51 | String[] kvs = routingEntry.split("@"); 52 | if (kvs.length == 2) { 53 | String svcName = kvs[0]; 54 | String urlString = kvs[1]; 55 | routingTable.put(svcName, urlString); 56 | logger.info("added route entry key = " + svcName + ", value = " + urlString); 57 | } 58 | } 59 | if (routingTable.size() > 0) { 60 | routingTableRef.set(routingTable); 61 | logger.info("routing table updated, entry size " + routingTable.size()); 62 | } else { 63 | logger.info("routing table is not updated, entry size is 0"); 64 | } 65 | } 66 | 67 | @Override 68 | public boolean shouldFilter() { 69 | RequestContext ctx = RequestContext.getCurrentContext(); 70 | return ctx.sendZuulResponse(); 71 | } 72 | 73 | // sample url 74 | // http://api.spring2go.com/api/hello 75 | @Override 76 | public Object run() throws ZuulException { 77 | RequestContext ctx = RequestContext.getCurrentContext(); 78 | String path = ctx.getRequest().getRequestURI(); 79 | String requestPath = ""; 80 | String serviceName = ""; 81 | String requestMethod = ""; 82 | int index = path.lastIndexOf("/api/"); 83 | if (index > 0) { 84 | requestPath = path.substring(index + 5); 85 | if (StringUtils.isNotEmpty(requestPath)) { 86 | int index2 = requestPath.indexOf("/"); 87 | if (index2 > 0) { 88 | serviceName = requestPath.substring(0, index2); 89 | requestMethod = requestPath.substring(index2 + 1); 90 | } else { 91 | serviceName = requestPath; 92 | } 93 | } 94 | } 95 | if (StringUtils.isNotEmpty(serviceName)) { 96 | String urlString = routingTableRef.get().get(serviceName); 97 | if (StringUtils.isNotEmpty(urlString)) { 98 | if (StringUtils.isNotEmpty(requestMethod)) { 99 | urlString = urlString.endsWith("/") ? urlString + requestMethod : urlString + "/" + requestMethod; 100 | } 101 | URL url; 102 | try { 103 | url = new URL(urlString); 104 | ctx.setRouteUrl(url); 105 | } catch (MalformedURLException e) { 106 | throw new ZuulException(e, "Malformed URL exception", 500, "Malformed URL exception"); 107 | } 108 | } 109 | } 110 | 111 | if (ctx.getRouteUrl() == null) { 112 | throw new ZuulException("No route found", 404, "No route found"); 113 | } 114 | 115 | return null; 116 | } 117 | 118 | @Override 119 | public String filterType() { 120 | return "pre"; 121 | } 122 | 123 | @Override 124 | public int filterOrder() { 125 | return 20; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/Counter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import com.netflix.servo.DefaultMonitorRegistry; 4 | import com.netflix.servo.monitor.BasicCounter; 5 | import com.netflix.servo.monitor.MonitorConfig; 6 | import com.netflix.servo.tag.InjectableTag; 7 | import com.netflix.servo.tag.Tag; 8 | 9 | import io.spring2go.zuul.monitoring.CounterFactory; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | import java.util.concurrent.ConcurrentMap; 15 | 16 | /** 17 | * Plugin to hook up a Servo counter to the CounterFactory 18 | */ 19 | public class Counter extends CounterFactory { 20 | final static ConcurrentMap map = new ConcurrentHashMap(); 21 | final Object lock = new Object(); 22 | 23 | @Override 24 | public void increment(String name) { 25 | BasicCounter counter = getCounter(name); 26 | counter.increment(); 27 | } 28 | 29 | private BasicCounter getCounter(String name) { 30 | BasicCounter counter = map.get(name); 31 | if (counter == null) { 32 | synchronized (lock) { 33 | counter = map.get(name); 34 | if (counter != null) { 35 | return counter; 36 | } 37 | 38 | List tags = new ArrayList(2); 39 | tags.add(InjectableTag.HOSTNAME); 40 | tags.add(InjectableTag.IP); 41 | counter = new BasicCounter(MonitorConfig.builder(name).withTags(tags).build()); 42 | map.putIfAbsent(name, counter); 43 | DefaultMonitorRegistry.getInstance().register(counter); 44 | } 45 | } 46 | return counter; 47 | } 48 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/CounterFactory.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | /** 4 | * Abstraction layer to provide counter based monitoring. 5 | * 6 | */ 7 | public abstract class CounterFactory { 8 | 9 | private static CounterFactory instance; 10 | 11 | /** 12 | * Pass in a CounterFactory Instance. This must be done to use Zuul as Zuul uses several internal counters 13 | * 14 | * @param f a CounterFactory value 15 | */ 16 | public static final void initialize(CounterFactory f) { 17 | instance = f; 18 | } 19 | 20 | /** 21 | * return the singleton CounterFactory instance. 22 | * 23 | * @return a CounterFactory value 24 | */ 25 | public static final CounterFactory instance() { 26 | if(instance == null) throw new IllegalStateException(String.format("%s not initialized", CounterFactory.class.getSimpleName())); 27 | return instance; 28 | } 29 | 30 | /** 31 | * Increments the counter of the given name 32 | * 33 | * @param name a String value 34 | */ 35 | public abstract void increment(String name); 36 | 37 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/ErrorStatsData.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import com.netflix.servo.annotations.DataSourceType; 4 | import com.netflix.servo.annotations.Monitor; 5 | import com.netflix.servo.annotations.MonitorTags; 6 | import com.netflix.servo.tag.BasicTag; 7 | import com.netflix.servo.tag.BasicTagList; 8 | import com.netflix.servo.tag.TagList; 9 | import io.spring2go.zuul.common.INamedCount; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.runners.MockitoJUnitRunner; 13 | 14 | import java.util.concurrent.atomic.AtomicLong; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | import static org.junit.Assert.assertFalse; 18 | import static org.junit.Assert.assertTrue; 19 | 20 | /** 21 | * Implementation of a Named counter to monitor and count error causes by route. Route is a defined zuul concept to 22 | * categorize requests into buckets. By default this is the first segment of the uri 23 | */ 24 | public class ErrorStatsData implements INamedCount 25 | { 26 | 27 | 28 | String id; 29 | 30 | @MonitorTags 31 | TagList tagList; 32 | 33 | String error_cause; 34 | 35 | @Monitor(name = "count", type = DataSourceType.COUNTER) 36 | AtomicLong count = new AtomicLong(); 37 | 38 | /** 39 | * create a counter by route and cause of error 40 | * @param route 41 | * @param cause 42 | */ 43 | public ErrorStatsData(String route, String cause) { 44 | if(null == route || "".equals(route)){ 45 | route = "UNKNOWN"; 46 | } 47 | id = route + "_" + cause; 48 | 49 | this.error_cause = cause; 50 | tagList = BasicTagList.of(new BasicTag("ID", id)); 51 | 52 | 53 | 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (o == null || getClass() != o.getClass()) return false; 60 | 61 | ErrorStatsData that = (ErrorStatsData) o; 62 | 63 | return !(error_cause != null ? !error_cause.equals(that.error_cause) : that.error_cause != null); 64 | 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return error_cause != null ? error_cause.hashCode() : 0; 70 | } 71 | 72 | /** 73 | * increments the counter 74 | */ 75 | public void update() { 76 | count.incrementAndGet(); 77 | } 78 | 79 | @Override 80 | public String getName() { 81 | return id; 82 | } 83 | 84 | @Override 85 | public long getCount() { 86 | return count.get(); 87 | } 88 | 89 | @RunWith(MockitoJUnitRunner.class) 90 | public static class UnitTest { 91 | 92 | @Test 93 | public void testUpdateStats() { 94 | ErrorStatsData sd = new ErrorStatsData("route", "test"); 95 | assertEquals(sd.error_cause, "test"); 96 | sd.update(); 97 | assertEquals(sd.count.get(), 1); 98 | sd.update(); 99 | assertEquals(sd.count.get(), 2); 100 | } 101 | 102 | 103 | @Test 104 | public void testEquals() { 105 | ErrorStatsData sd = new ErrorStatsData("route", "test"); 106 | ErrorStatsData sd1 = new ErrorStatsData("route", "test"); 107 | ErrorStatsData sd2 = new ErrorStatsData("route", "test1"); 108 | ErrorStatsData sd3 = new ErrorStatsData("route", "test"); 109 | 110 | assertTrue(sd.equals(sd1)); 111 | assertTrue(sd1.equals(sd)); 112 | assertTrue(sd.equals(sd)); 113 | assertFalse(sd.equals(sd2)); 114 | assertFalse(sd2.equals(sd3)); 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/ErrorStatsManager.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import io.spring2go.zuul.context.RequestContext; 4 | import io.spring2go.zuul.monitoring.MonitorRegistry; 5 | 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.runners.MockitoJUnitRunner; 9 | 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assert.assertNotNull; 15 | 16 | /** 17 | * Manager to handle Error Statistics 18 | */ 19 | public class ErrorStatsManager { 20 | ConcurrentHashMap> routeMap = new ConcurrentHashMap>(); 21 | final static ErrorStatsManager INSTANCE = new ErrorStatsManager(); 22 | 23 | /** 24 | * 25 | * @return Singleton 26 | */ 27 | public static ErrorStatsManager getManager() { 28 | return INSTANCE; 29 | } 30 | 31 | 32 | /** 33 | * 34 | * @param route 35 | * @param cause 36 | * @return data structure for holding count information for a route and cause 37 | */ 38 | public ErrorStatsData getStats(String route, String cause) { 39 | Map map = routeMap.get(route); 40 | if (map == null) return null; 41 | return map.get(cause); 42 | } 43 | 44 | /** 45 | * updates count for the given route and error cause 46 | * @param route 47 | * @param cause 48 | */ 49 | public void putStats(String route, String cause) { 50 | if (route == null) route = RequestContext.getCurrentContext().getRequest().getRequestURI(); 51 | if (route == null) route = "UNKNOWN_ROUTE"; 52 | route = route.replace("/", "_"); 53 | ConcurrentHashMap statsMap = routeMap.get(route); 54 | if (statsMap == null) { 55 | statsMap = new ConcurrentHashMap(); 56 | routeMap.putIfAbsent(route, statsMap); 57 | } 58 | ErrorStatsData sd = statsMap.get(cause); 59 | if (sd == null) { 60 | sd = new ErrorStatsData(route, cause); 61 | ErrorStatsData sd1 = statsMap.putIfAbsent(cause, sd); 62 | if (sd1 != null) { 63 | sd = sd1; 64 | } else { 65 | MonitorRegistry.getInstance().registerObject(sd); 66 | } 67 | } 68 | sd.update(); 69 | } 70 | 71 | 72 | @RunWith(MockitoJUnitRunner.class) 73 | public static class UnitTest { 74 | 75 | @Test 76 | public void testPutStats() { 77 | ErrorStatsManager sm = new ErrorStatsManager(); 78 | assertNotNull(sm); 79 | sm.putStats("test", "cause"); 80 | assertNotNull(sm.routeMap.get("test")); 81 | ConcurrentHashMap map = sm.routeMap.get("test"); 82 | ErrorStatsData sd = map.get("cause"); 83 | assertEquals(sd.count.get(), 1); 84 | sm.putStats("test", "cause"); 85 | assertEquals(sd.count.get(), 2); 86 | } 87 | 88 | 89 | @Test 90 | public void testGetStats() { 91 | ErrorStatsManager sm = new ErrorStatsManager(); 92 | assertNotNull(sm); 93 | sm.putStats("test", "cause"); 94 | assertNotNull(sm.getStats("test", "cause")); 95 | } 96 | 97 | } 98 | 99 | 100 | } 101 | 102 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/MetricPoller.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import com.netflix.servo.publish.BasicMetricFilter; 4 | import com.netflix.servo.publish.CounterToRateMetricTransform; 5 | import com.netflix.servo.publish.FileMetricObserver; 6 | import com.netflix.servo.publish.MetricObserver; 7 | import com.netflix.servo.publish.MonitorRegistryMetricPoller; 8 | import com.netflix.servo.publish.PollRunnable; 9 | import com.netflix.servo.publish.PollScheduler; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * Sample poller to poll metrics using Servo's metric publication 19 | */ 20 | public class MetricPoller { 21 | 22 | private static Logger LOG = LoggerFactory.getLogger(MetricPoller.class); 23 | 24 | final static PollScheduler scheduler = PollScheduler.getInstance(); 25 | 26 | public static void startPoller(){ 27 | scheduler.start(); 28 | final int heartbeatInterval = 1200; 29 | 30 | final File metricsDir; 31 | try { 32 | metricsDir = File.createTempFile("zuul-servo-metrics-", ""); 33 | metricsDir.delete(); 34 | metricsDir.mkdir(); 35 | } catch (IOException e) { 36 | throw new RuntimeException(e); 37 | } 38 | 39 | LOG.debug("created metrics dir " + metricsDir.getAbsolutePath()); 40 | 41 | MetricObserver transform = new CounterToRateMetricTransform( 42 | new FileMetricObserver("ZuulMetrics", metricsDir), 43 | heartbeatInterval, TimeUnit.SECONDS); 44 | 45 | PollRunnable task = new PollRunnable( 46 | new MonitorRegistryMetricPoller(), 47 | BasicMetricFilter.MATCH_ALL, 48 | transform); 49 | 50 | final int samplingInterval = 10; 51 | scheduler.addPoller(task, samplingInterval, TimeUnit.SECONDS); 52 | 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/MonitorRegistry.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import io.spring2go.zuul.common.IMonitor; 4 | import io.spring2go.zuul.common.INamedCount; 5 | 6 | public class MonitorRegistry { 7 | 8 | private static final MonitorRegistry instance = new MonitorRegistry(); 9 | private IMonitor publisher; 10 | 11 | /** 12 | * A Monitor implementation should be set here 13 | * @param publisher 14 | */ 15 | public void setPublisher(IMonitor publisher) { 16 | this.publisher = publisher; 17 | } 18 | 19 | 20 | 21 | public static MonitorRegistry getInstance() { 22 | return instance; 23 | } 24 | 25 | public void registerObject(INamedCount monitorObj) { 26 | if(publisher != null) publisher.register(monitorObj); 27 | } 28 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/NamedCountingMonitor.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.netflix.servo.annotations.DataSourceType; 6 | import com.netflix.servo.annotations.Monitor; 7 | import com.netflix.servo.annotations.MonitorTags; 8 | import com.netflix.servo.tag.BasicTagList; 9 | import com.netflix.servo.tag.TagList; 10 | import io.spring2go.zuul.common.INamedCount; 11 | 12 | public class NamedCountingMonitor implements INamedCount { 13 | 14 | private final String name; 15 | 16 | @MonitorTags 17 | TagList tagList; 18 | @Monitor(name = "count", type = DataSourceType.COUNTER) 19 | private final AtomicLong count = new AtomicLong(); 20 | 21 | public NamedCountingMonitor(String name) { 22 | this.name = name; 23 | tagList = BasicTagList.of("ID", name); 24 | } 25 | 26 | /** 27 | * reguisters this objects 28 | * 29 | * @return 30 | */ 31 | public NamedCountingMonitor register() { 32 | MonitorRegistry.getInstance().registerObject(this); 33 | return this; 34 | } 35 | 36 | /** 37 | * increments the counter 38 | * 39 | * @return 40 | */ 41 | public long increment() { 42 | return this.count.incrementAndGet(); 43 | } 44 | 45 | @Override 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | /** 51 | * @return the current count 52 | */ 53 | public long getCount() { 54 | return this.count.get(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/RouteErrorMonitor.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.netflix.servo.annotations.DataSourceType; 6 | import com.netflix.servo.annotations.Monitor; 7 | import com.netflix.servo.annotations.MonitorTags; 8 | import com.netflix.servo.tag.BasicTag; 9 | import com.netflix.servo.tag.BasicTagList; 10 | import com.netflix.servo.tag.TagList; 11 | import io.spring2go.zuul.common.INamedCount; 12 | 13 | /** 14 | * Implementation of a Named counter to monitor and count error causes by route. Route is a defined zuul gateway concept to 15 | * categorize requests into buckets. By default this is the first segment of the uri 16 | * 17 | */ 18 | public class RouteErrorMonitor implements INamedCount { 19 | 20 | String id; 21 | String error_cause; 22 | 23 | @MonitorTags 24 | TagList tagList; 25 | @Monitor(name = "count", type = DataSourceType.COUNTER) 26 | AtomicLong count = new AtomicLong(); 27 | 28 | /** 29 | * create a counter by route and cause of error 30 | * 31 | * @param route 32 | * @param cause 33 | */ 34 | public RouteErrorMonitor(String route, String cause) { 35 | if (null == route || "".equals(route)) { 36 | route = "UNKNOWN"; 37 | } 38 | id = route + "_" + cause; 39 | 40 | this.error_cause = cause; 41 | tagList = BasicTagList.of(new BasicTag("ID", id)); 42 | 43 | 44 | } 45 | 46 | @Override 47 | public boolean equals(Object o) { 48 | if (this == o) return true; 49 | if (o == null || getClass() != o.getClass()) return false; 50 | 51 | RouteErrorMonitor that = (RouteErrorMonitor) o; 52 | 53 | return !(error_cause != null ? !error_cause.equals(that.error_cause) : that.error_cause != null); 54 | 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return error_cause != null ? error_cause.hashCode() : 0; 60 | } 61 | 62 | /** 63 | * increments the counter 64 | */ 65 | public void update() { 66 | count.incrementAndGet(); 67 | } 68 | 69 | @Override 70 | public String getName() { 71 | return id; 72 | } 73 | 74 | @Override 75 | public long getCount() { 76 | return count.get(); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/RouteStatusCodeMonitor.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.netflix.servo.annotations.DataSourceType; 6 | import com.netflix.servo.annotations.Monitor; 7 | import com.netflix.servo.annotations.MonitorTags; 8 | import com.netflix.servo.tag.BasicTag; 9 | import com.netflix.servo.tag.BasicTagList; 10 | import com.netflix.servo.tag.TagList; 11 | import io.spring2go.zuul.common.INamedCount; 12 | 13 | public class RouteStatusCodeMonitor implements INamedCount { 14 | 15 | String route_code; 16 | String route; 17 | int status_code; 18 | 19 | @MonitorTags 20 | TagList tagList; 21 | @Monitor(name = "count", type = DataSourceType.COUNTER) 22 | protected final AtomicLong count = new AtomicLong(); 23 | 24 | public RouteStatusCodeMonitor(String route, int status_code) { 25 | if (route == null) route = ""; 26 | this.route = route; 27 | this.status_code = status_code; 28 | route_code = route + "_" + status_code; 29 | tagList = BasicTagList.of(new BasicTag("ID", route_code)); 30 | } 31 | 32 | @Override 33 | public boolean equals(Object o) { 34 | if (this == o) return true; 35 | if (o == null || getClass() != o.getClass()) return false; 36 | 37 | RouteStatusCodeMonitor statsData = (RouteStatusCodeMonitor) o; 38 | 39 | if (status_code != statsData.status_code) return false; 40 | if (route != null ? !route.equals(statsData.route) : statsData.route != null) return false; 41 | 42 | return true; 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | int result = route != null ? route.hashCode() : 0; 48 | result = 31 * result + status_code; 49 | return result; 50 | } 51 | 52 | @Override 53 | public String getName() { 54 | return route_code; 55 | } 56 | 57 | public long getCount() { 58 | return count.get(); 59 | } 60 | 61 | /** 62 | * increment the count 63 | */ 64 | public void update() { 65 | count.incrementAndGet(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/ServoMonitor.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import com.netflix.servo.monitor.Monitors; 4 | import io.spring2go.zuul.common.IMonitor; 5 | import io.spring2go.zuul.common.INamedCount; 6 | 7 | public class ServoMonitor implements IMonitor { 8 | @Override 9 | public void register(INamedCount monitorObj) { 10 | Monitors.registerObject(monitorObj); 11 | } 12 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/Tracer.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import com.netflix.servo.monitor.DynamicTimer; 8 | import com.netflix.servo.monitor.MonitorConfig; 9 | import com.netflix.servo.monitor.Stopwatch; 10 | import com.netflix.servo.tag.InjectableTag; 11 | import com.netflix.servo.tag.Tag; 12 | import io.spring2go.zuul.common.ITracer; 13 | 14 | public class Tracer extends TracerFactory { 15 | 16 | static List tags = new ArrayList(2); 17 | 18 | static { 19 | tags.add(InjectableTag.HOSTNAME); 20 | tags.add(InjectableTag.IP); 21 | } 22 | 23 | @Override 24 | public ITracer startMicroTracer(String name) { 25 | return new ServoTracer(name); 26 | } 27 | 28 | class ServoTracer implements ITracer { 29 | 30 | final MonitorConfig config; 31 | final Stopwatch stopwatch; 32 | 33 | private ServoTracer(String name) { 34 | config = MonitorConfig.builder(name).withTags(tags).build(); 35 | stopwatch = DynamicTimer.start(config, TimeUnit.MICROSECONDS); 36 | } 37 | 38 | @Override 39 | public void stopAndLog() { 40 | DynamicTimer.record(config, stopwatch.getDuration()); 41 | } 42 | 43 | @Override 44 | public void setName(String name) { 45 | 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/monitoring/TracerFactory.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.monitoring; 2 | 3 | import io.spring2go.zuul.common.ITracer; 4 | 5 | /** 6 | * Abstraction layer to provide time-based monitoring. 7 | * 8 | */ 9 | public abstract class TracerFactory { 10 | 11 | private static TracerFactory instance; 12 | 13 | /** 14 | * sets a TracerFactory Implementation 15 | * 16 | * @param f a TracerFactory value 17 | */ 18 | public static final void initialize(TracerFactory f) { 19 | instance = f; 20 | } 21 | 22 | 23 | /** 24 | * Returns the singleton TracerFactory 25 | * 26 | * @return a TracerFactory value 27 | */ 28 | public static final TracerFactory instance() { 29 | if(instance == null) throw new IllegalStateException(String.format("%s not initialized", TracerFactory.class.getSimpleName())); 30 | return instance; 31 | } 32 | 33 | public abstract ITracer startMicroTracer(String name); 34 | 35 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/servlet/CatServletFilter.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.servlet; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import javax.servlet.Filter; 8 | import javax.servlet.FilterChain; 9 | import javax.servlet.FilterConfig; 10 | import javax.servlet.ServletException; 11 | import javax.servlet.ServletRequest; 12 | import javax.servlet.ServletResponse; 13 | import javax.servlet.http.HttpServletRequest; 14 | 15 | import com.dianping.cat.Cat; 16 | import com.dianping.cat.message.Message; 17 | import com.dianping.cat.message.Transaction; 18 | 19 | import io.spring2go.zuul.common.Constants; 20 | 21 | public class CatServletFilter implements Filter { 22 | 23 | private String[] urlPatterns = new String[0]; 24 | 25 | @Override 26 | public void init(FilterConfig filterConfig) throws ServletException { 27 | String patterns = filterConfig.getInitParameter("CatHttpModuleUrlPatterns"); 28 | if (patterns != null) { 29 | patterns = patterns.trim(); 30 | urlPatterns = patterns.split(","); 31 | for (int i = 0; i < urlPatterns.length; i++) { 32 | urlPatterns[i] = urlPatterns[i].trim(); 33 | } 34 | } 35 | } 36 | 37 | @Override 38 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 39 | 40 | HttpServletRequest request = (HttpServletRequest) servletRequest; 41 | 42 | String url = request.getRequestURL().toString(); 43 | for (String urlPattern : urlPatterns) { 44 | if (url.startsWith(urlPattern)) { 45 | url = urlPattern; 46 | } 47 | } 48 | 49 | Transaction t = Cat.newTransaction("Service", url); 50 | 51 | try { 52 | 53 | PropertyContext propertyContext = new PropertyContext(); 54 | propertyContext.addProperty(Cat.Context.ROOT, request.getHeader(Constants.CAT_ROOT_MESSAGE_ID)); 55 | propertyContext.addProperty(Cat.Context.PARENT, request.getHeader(Constants.CAT_PARENT_MESSAGE_ID)); 56 | propertyContext.addProperty(Cat.Context.CHILD, request.getHeader(Constants.CAT_CHILD_MESSAGE_ID)); 57 | Cat.logRemoteCallServer(propertyContext); 58 | 59 | Cat.logEvent("Service.method", request.getMethod(), Message.SUCCESS, request.getRequestURL().toString()); 60 | Cat.logEvent("Service.client", request.getRemoteHost()); 61 | 62 | filterChain.doFilter(servletRequest, servletResponse); 63 | 64 | t.setStatus(Transaction.SUCCESS); 65 | } catch (Exception ex) { 66 | t.setStatus(ex); 67 | Cat.logError(ex); 68 | throw ex; 69 | } finally { 70 | t.complete(); 71 | } 72 | } 73 | 74 | @Override 75 | public void destroy() { 76 | 77 | } 78 | 79 | class PropertyContext implements Cat.Context { 80 | 81 | private Map properties = new HashMap<>(); 82 | 83 | @Override 84 | public void addProperty(String key, String value) { 85 | properties.put(key, value); 86 | } 87 | 88 | @Override 89 | public String getProperty(String key) { 90 | return properties.get(key); 91 | } 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/AdminFilterUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import io.spring2go.zuul.common.FilterInfo; 4 | import io.spring2go.zuul.filters.FilterScriptManagerServlet; 5 | 6 | /** 7 | * Utility method to build form data for the Admin page for uploading and downloading filters 8 | * 9 | */ 10 | public class AdminFilterUtil { 11 | 12 | public static String getState(FilterInfo filter) { 13 | String state = "inactive"; 14 | if(filter.isActive())state = "active"; 15 | if(filter.isCanary())state = "canary"; 16 | return state; 17 | 18 | } 19 | 20 | public static String buildDeactivateForm(String filter_id, int revision) { 21 | if (FilterScriptManagerServlet.adminEnabled.get()) { 22 | return "

\n" + 23 | "
"; 24 | } else { 25 | return ""; 26 | } 27 | } 28 | 29 | public static String buildActivateForm(String filter_id, int revision) { 30 | if (FilterScriptManagerServlet.adminEnabled.get()) { 31 | return "
\n" + 32 | "
"; 33 | } else { 34 | return ""; 35 | } 36 | } 37 | 38 | public static String buildCanaryForm(String filter_id, int revision) { 39 | if (FilterScriptManagerServlet.adminEnabled.get()) { 40 | return "
\n" + 41 | "
"; 42 | } else { 43 | return ""; 44 | } 45 | } 46 | 47 | public static String buildDownloadLink(String filter_id, int revision) { 48 | return "DOWNLOAD"; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/Debug.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import io.spring2go.zuul.context.RequestContext; 8 | 9 | /** 10 | * Simple wrapper class around the RequestContext for setting and managing Request level Debug data. 11 | */ 12 | public class Debug { 13 | 14 | public static void setDebugRequest(boolean bDebug) { 15 | RequestContext.getCurrentContext().setDebugRequest(bDebug); 16 | } 17 | 18 | public static void setDebugRequestHeadersOnly(boolean bHeadersOnly) { 19 | RequestContext.getCurrentContext().setDebugRequestHeadersOnly(bHeadersOnly); 20 | } 21 | 22 | public static boolean debugRequestHeadersOnly() { 23 | return RequestContext.getCurrentContext().debugRequestHeadersOnly(); 24 | } 25 | 26 | 27 | public static void setDebugRouting(boolean bDebug) { 28 | RequestContext.getCurrentContext().setDebugRouting(bDebug); 29 | } 30 | 31 | 32 | public static boolean debugRequest() { 33 | return RequestContext.getCurrentContext().debugRequest(); 34 | } 35 | 36 | public static boolean debugRouting() { 37 | return RequestContext.getCurrentContext().debugRouting(); 38 | } 39 | 40 | public static void addRoutingDebug(String line) { 41 | List rd = getRoutingDebug(); 42 | rd.add(line); 43 | } 44 | 45 | /** 46 | * 47 | * @return Returns the list of routiong debug messages 48 | */ 49 | public static List getRoutingDebug() { 50 | List rd = (List) RequestContext.getCurrentContext().get("routingDebug"); 51 | if (rd == null) { 52 | rd = new ArrayList(); 53 | RequestContext.getCurrentContext().set("routingDebug", rd); 54 | } 55 | return rd; 56 | } 57 | 58 | /** 59 | * Adds a line to the Request debug messages 60 | * @param line 61 | */ 62 | public static void addRequestDebug(String line) { 63 | List rd = getRequestDebug(); 64 | rd.add(line); 65 | } 66 | 67 | /** 68 | * 69 | * @return returns the list of request debug messages 70 | */ 71 | public static List getRequestDebug() { 72 | List rd = (List) RequestContext.getCurrentContext().get("requestDebug"); 73 | if (rd == null) { 74 | rd = new ArrayList(); 75 | RequestContext.getCurrentContext().set("requestDebug", rd); 76 | } 77 | return rd; 78 | } 79 | 80 | 81 | /** 82 | * Adds debug details about changes that a given filter made to the request context. 83 | * @param filterName 84 | * @param copy 85 | */ 86 | public static void compareContextState(String filterName, RequestContext copy) { 87 | RequestContext context = RequestContext.getCurrentContext(); 88 | Iterator it = context.keySet().iterator(); 89 | String key = it.next(); 90 | while (key != null) { 91 | if ((!key.equals("routingDebug") && !key.equals("requestDebug"))) { 92 | Object newValue = context.get(key); 93 | Object oldValue = copy.get(key); 94 | if (oldValue == null && newValue != null) { 95 | addRoutingDebug("{" + filterName + "} added " + key + "=" + newValue.toString()); 96 | } else if (oldValue != null && newValue != null) { 97 | if (!(oldValue.equals(newValue))) { 98 | addRoutingDebug("{" +filterName + "} changed " + key + "=" + newValue.toString()); 99 | } 100 | } 101 | } 102 | if (it.hasNext()) { 103 | key = it.next(); 104 | } else { 105 | key = null; 106 | } 107 | } 108 | 109 | } 110 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/DeepCopy.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import java.io.*; 4 | 5 | public class DeepCopy { 6 | /** 7 | * Returns a copy of the object, or null if the object cannot be serialized. 8 | * 9 | * @param orig 10 | * an Object value 11 | * @return a deep copy of that Object 12 | * @exception NotSerializableException 13 | * if an error occurs 14 | */ 15 | public static Object copy(Object orig) throws NotSerializableException { 16 | Object obj = null; 17 | try { 18 | // Write the object out to a byte array 19 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 20 | ObjectOutputStream out = new ObjectOutputStream(bos); 21 | out.writeObject(orig); 22 | out.flush(); 23 | out.close(); 24 | 25 | // Make an input stream from the byte array and read 26 | // a copy of the object back in. 27 | ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); 28 | obj = in.readObject(); 29 | } catch (NotSerializableException e) { 30 | throw e; 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } catch (ClassNotFoundException cnfe) { 34 | cnfe.printStackTrace(); 35 | } 36 | return obj; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import java.io.IOException; 4 | import java.nio.charset.Charset; 5 | import java.util.Map; 6 | 7 | import org.apache.http.HttpEntity; 8 | import org.apache.http.client.ClientProtocolException; 9 | import org.apache.http.client.methods.CloseableHttpResponse; 10 | import org.apache.http.client.methods.HttpPost; 11 | import org.apache.http.entity.StringEntity; 12 | import org.apache.http.impl.client.CloseableHttpClient; 13 | import org.apache.http.util.EntityUtils; 14 | 15 | import com.alibaba.fastjson.JSON; 16 | import com.alibaba.fastjson.serializer.SerializerFeature; 17 | 18 | public class HttpUtil { 19 | 20 | 21 | public static T postData(CloseableHttpClient httpClient,String url, Object par, Map header, Class clazz) 22 | throws ClientProtocolException, IOException { 23 | HttpPost method = new HttpPost(url); 24 | method.setHeader("Content-type", "application/json; charset=utf-8"); 25 | method.setHeader("Accept", "application/json"); 26 | if (header != null) { 27 | for (String key : header.keySet()) { 28 | method.setHeader(key, header.get(key)); 29 | } 30 | } 31 | if (par != null) { 32 | String parameters = JSON.toJSONString(par, SerializerFeature.DisableCircularReferenceDetect); 33 | HttpEntity entity = new StringEntity(parameters, Charset.forName("UTF-8")); 34 | method.setEntity(entity); 35 | } 36 | CloseableHttpResponse response = httpClient.execute(method); 37 | String body = EntityUtils.toString(response.getEntity()); 38 | return JSON.parseObject(body, clazz); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/IPUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import java.net.Inet6Address; 4 | import java.net.InetAddress; 5 | import java.net.NetworkInterface; 6 | import java.net.SocketException; 7 | import java.util.Enumeration; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | 11 | import org.apache.commons.lang.StringUtils; 12 | 13 | public class IPUtil { 14 | private static final String NETWORK_CARD = "eth0"; 15 | private static final String NETWORK_CARD_BAND = "bond0"; 16 | 17 | public static String getLocalHostName() { 18 | try { 19 | InetAddress addr = InetAddress.getLocalHost(); 20 | return addr.getHostName(); 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | return ""; 24 | } 25 | } 26 | 27 | public static String getLinuxLocalIP() { 28 | String ip = ""; 29 | try { 30 | Enumeration e1 = (Enumeration) NetworkInterface.getNetworkInterfaces(); 31 | while (e1.hasMoreElements()) { 32 | NetworkInterface ni = e1.nextElement(); 33 | if ((NETWORK_CARD.equals(ni.getName())) || (NETWORK_CARD_BAND.equals(ni.getName()))) { 34 | Enumeration e2 = ni.getInetAddresses(); 35 | while (e2.hasMoreElements()) { 36 | InetAddress ia = e2.nextElement(); 37 | if (ia instanceof Inet6Address) { 38 | continue; 39 | } 40 | ip = ia.getHostAddress(); 41 | } 42 | break; 43 | } else { 44 | continue; 45 | } 46 | } 47 | } catch (SocketException e) { 48 | e.printStackTrace(); 49 | } 50 | return ip; 51 | } 52 | 53 | public static String getWinLocalIP() { 54 | String ip = null; 55 | try { 56 | ip = InetAddress.getLocalHost().getHostAddress().toString(); 57 | } finally { 58 | return ip; 59 | } 60 | } 61 | 62 | public static String getLocalIP() { 63 | String ip = null; 64 | if (!System.getProperty("os.name").contains("Win")) { 65 | ip = getLinuxLocalIP(); 66 | } else { 67 | 68 | ip = getWinLocalIP(); 69 | } 70 | return ip; 71 | } 72 | 73 | public static String getClientIpAddr(HttpServletRequest request) { 74 | String ip = request.getHeader("x-forwarded-for"); 75 | if(StringUtils.isEmpty(ip) ||"unknown".equalsIgnoreCase(ip)) { 76 | ip = request.getHeader("Proxy-Client-IP"); 77 | } 78 | if(StringUtils.isEmpty(ip) ||"unknown".equalsIgnoreCase(ip)) { 79 | ip = request.getHeader("WL-Proxy-Client-IP"); 80 | } 81 | if(StringUtils.isEmpty(ip) ||"unknown".equalsIgnoreCase(ip)) { 82 | ip = request.getRemoteAddr(); 83 | } 84 | if(!StringUtils.isEmpty(ip)){ 85 | ip=ip.split(",")[0]; 86 | } 87 | return ip; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/MonitoringUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import io.spring2go.zuul.common.ITracer; 4 | import io.spring2go.zuul.monitoring.CounterFactory; 5 | import io.spring2go.zuul.monitoring.TracerFactory; 6 | 7 | /** 8 | * Dummy implementations of CounterFactory, TracerFactory, and Tracer 9 | */ 10 | public class MonitoringUtil { 11 | 12 | public static final void initMocks() { 13 | CounterFactory.initialize(new CounterFactoryImpl()); 14 | TracerFactory.initialize(new TracerFactoryImpl()); 15 | } 16 | 17 | private static final class CounterFactoryImpl extends CounterFactory { 18 | @Override 19 | public void increment(String name) {} 20 | } 21 | 22 | private static final class TracerFactoryImpl extends TracerFactory { 23 | @Override 24 | public ITracer startMicroTracer(String name) { 25 | return new TracerImpl(); 26 | } 27 | } 28 | 29 | private static final class TracerImpl implements ITracer { 30 | @Override 31 | public void setName(String name) {} 32 | 33 | @Override 34 | public void stopAndLog() {} 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/S2gUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | 8 | import org.apache.commons.lang.StringUtils; 9 | 10 | public class S2gUtil { 11 | public static boolean contains(String[] srcTags, String[] dstTags) { 12 | if (dstTags == null || dstTags.length == 0) 13 | return true; 14 | 15 | if (srcTags == null || srcTags.length == 0) 16 | return false; 17 | 18 | List srcTagList = Arrays.asList(srcTags); 19 | for (String t : dstTags) { 20 | if (!srcTagList.contains(t)) { 21 | return false; 22 | } 23 | } 24 | return true; 25 | } 26 | public static String trimEnd(String data,char trim){ 27 | data=StringUtils.trim(data); 28 | if (!StringUtils.isEmpty(data)&& (data.toCharArray()[data.length() - 1]) == trim) { 29 | data = data.substring(0, data.length() - 1); 30 | } 31 | return data; 32 | } 33 | public static String getServerletUrl(HttpServletRequest request) { 34 | //String url= request.getServletPath(); 35 | String uri = request.getRequestURI(); 36 | String contextPath = request.getContextPath(); 37 | if (StringUtils.length(contextPath) > 0) { 38 | uri = StringUtils.substring(uri, contextPath.length()); 39 | } 40 | if(StringUtils.length(uri) > 0){ 41 | uri=uri.substring(1, StringUtils.length(uri)); 42 | } 43 | String query= request.getQueryString(); 44 | if(!StringUtils.isEmpty(query)){ 45 | uri+="?"+query; 46 | } 47 | return uri; 48 | } 49 | public static String[] getRoutes(HttpServletRequest request) { 50 | return getServerletUrl(request).split("/"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/SleepUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | public class SleepUtil { 4 | 5 | private SleepUtil() { 6 | } 7 | 8 | public static void sleep(long timeout) { 9 | try { 10 | Thread.sleep(timeout); 11 | } catch (Throwable t) { 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/java/io/spring2go/zuul/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.apache.commons.lang.StringUtils; 7 | 8 | public class StringUtil { 9 | 10 | public static boolean contains(String[] srcTags, String[] dstTags) { 11 | if (dstTags == null || dstTags.length == 0) 12 | return true; 13 | 14 | if (srcTags == null || srcTags.length == 0) 15 | return false; 16 | 17 | List srcTagList = Arrays.asList(srcTags); 18 | for (String t : dstTags) { 19 | if (!srcTagList.contains(t)) { 20 | return false; 21 | } 22 | } 23 | return true; 24 | } 25 | 26 | public static String trimEnd(String data, char trim) { 27 | data = StringUtils.trim(data); 28 | if (!StringUtils.isEmpty(data) && (data.toCharArray()[data.length() - 1]) == trim) { 29 | data = data.substring(0, data.length() - 1); 30 | } 31 | return data; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /s2g-zuul-core/src/main/resources/content/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 34 | 35 | 94 | 95 | 96 |
97 | Status 98 | Environment 99 | Configuration 100 |
101 |
102 |
103 | 104 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | s2g-zuul 6 | io.spring2go.zuul 7 | 1.0.0 8 | 9 | 4.0.0 10 | 11 | s2g-zuul-mobile 12 | war 13 | 14 | 15 | 16 | com.squareup.okhttp 17 | okhttp 18 | 19 | 20 | 21 | io.reactivex 22 | rxjava 23 | 1.0.12 24 | 25 | 26 | 27 | io.spring2go.zuul 28 | s2g-zuul-core 29 | 30 | 31 | io.reactivex 32 | rxjava 33 | 34 | 35 | com.netflix.rxjava 36 | rxjava-core 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | s2g-zuul-mobile 45 | 46 | 47 | ${basedir}/src/main/resources 48 | 49 | **/*.properties 50 | **/*.xml 51 | **/*.tld 52 | **/*.config 53 | **/*.yml 54 | 55 | false 56 | 57 | 58 | src/main/resources 59 | true 60 | 61 | 62 | src/main/java 63 | 64 | 65 | 66 | maven-compiler-plugin 67 | 68 | 1.7 69 | 1.7 70 | utf8 71 | 72 | 73 | 74 | 75 | maven-surefire-plugin 76 | 77 | 78 | **/*Tests.java 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/java/io/spring2go/zuul/servlet/AsyncZuulListener.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.servlet; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.AsyncEvent; 6 | import javax.servlet.AsyncListener; 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public class AsyncZuulListener implements AsyncListener { 13 | private static final Logger LOGGER = LoggerFactory.getLogger(AsyncZuulListener.class); 14 | 15 | @Override 16 | public void onComplete(AsyncEvent event) throws IOException { 17 | } 18 | 19 | @Override 20 | public void onTimeout(AsyncEvent event) throws IOException { 21 | LOGGER.error("Access {} timeout in AsyncServlet.", ((HttpServletRequest)event.getAsyncContext().getRequest()).getRequestURL()); 22 | } 23 | 24 | @Override 25 | public void onError(AsyncEvent event) throws IOException { 26 | LOGGER.error("Error while access {} in AsyncServlet.", ((HttpServletRequest)event.getAsyncContext().getRequest()).getRequestURL()); 27 | } 28 | 29 | @Override 30 | public void onStartAsync(AsyncEvent event) throws IOException { 31 | } 32 | } -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/java/io/spring2go/zuul/servlet/SyncZuulServlet.java: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.servlet; 2 | 3 | import javax.servlet.http.HttpServlet; 4 | import javax.servlet.http.HttpServletRequest; 5 | import javax.servlet.http.HttpServletResponse; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.dianping.cat.Cat; 11 | import io.spring2go.zuul.common.ZuulException; 12 | import io.spring2go.zuul.context.RequestContext; 13 | import io.spring2go.zuul.core.ZuulRunner; 14 | 15 | public class SyncZuulServlet extends HttpServlet { 16 | 17 | private static final long serialVersionUID = -7314825620092836092L; 18 | 19 | private static Logger LOGGER = LoggerFactory.getLogger(SyncZuulServlet.class); 20 | 21 | private ZuulRunner zuulRunner = new ZuulRunner(); 22 | 23 | @Override 24 | public void service(javax.servlet.ServletRequest req, javax.servlet.ServletResponse res) throws javax.servlet.ServletException, java.io.IOException { 25 | try { 26 | 27 | 28 | init((HttpServletRequest) req, (HttpServletResponse) res); 29 | 30 | // marks this request as having passed through the "Zuul engine", as opposed to servlets 31 | // explicitly bound in web.xml, for which requests will not have the same data attached 32 | RequestContext.getCurrentContext().setZuulEngineRan(); 33 | 34 | try { 35 | preRoute(); 36 | } catch (ZuulException e) { 37 | error(e); 38 | postRoute(); 39 | return; 40 | } 41 | try { 42 | route(); 43 | } catch (ZuulException e) { 44 | error(e); 45 | postRoute(); 46 | return; 47 | } 48 | try { 49 | postRoute(); 50 | } catch (ZuulException e) { 51 | error(e); 52 | return; 53 | } 54 | 55 | } catch (Throwable e) { 56 | error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); 57 | } finally { 58 | RequestContext.getCurrentContext().unset(); 59 | } 60 | } 61 | 62 | /** 63 | * executes "post" ZuulFilters 64 | * 65 | * @throws ZuulException 66 | */ 67 | void postRoute() throws ZuulException { 68 | zuulRunner.postRoute(); 69 | } 70 | 71 | /** 72 | * executes "route" filters 73 | * 74 | * @throws ZuulException 75 | */ 76 | void route() throws ZuulException { 77 | zuulRunner.route(); 78 | } 79 | 80 | /** 81 | * executes "pre" filters 82 | * 83 | * @throws ZuulException 84 | */ 85 | void preRoute() throws ZuulException { 86 | zuulRunner.preRoute(); 87 | } 88 | 89 | /** 90 | * initializes request 91 | * 92 | * @param servletRequest 93 | * @param servletResponse 94 | */ 95 | void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { 96 | zuulRunner.init(servletRequest, servletResponse); 97 | } 98 | 99 | /** 100 | * sets error context info and executes "error" filters 101 | * 102 | * @param e 103 | * @throws ZuulException 104 | */ 105 | void error(ZuulException e) { 106 | try { 107 | RequestContext.getCurrentContext().setThrowable(e); 108 | zuulRunner.error(); 109 | } catch (Throwable t) { 110 | Cat.logError(t); 111 | LOGGER.error(e.getMessage(), e); 112 | }finally{ 113 | Cat.logError(e); 114 | } 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/.gitignore: -------------------------------------------------------------------------------- 1 | /mobile_zuul.properties 2 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/META-INF/app.properties: -------------------------------------------------------------------------------- 1 | app.name=mobile-zuul-gateway -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/db/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `zuul_filter` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', 3 | `filter_id` varchar(45) DEFAULT NULL COMMENT '过滤器id', 4 | `revision` int(11) DEFAULT NULL COMMENT '版本', 5 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 6 | `is_active` tinyint(1) DEFAULT '0' COMMENT '是否是活跃', 7 | `is_canary` tinyint(1) DEFAULT '0' COMMENT '是否是灰度', 8 | `filter_code` longtext COMMENT 'filter代码', 9 | `filter_type` varchar(45) DEFAULT NULL COMMENT 'filter类型', 10 | `filter_name` varchar(45) DEFAULT NULL COMMENT '名称', 11 | `disable_property_name` varchar(45) DEFAULT NULL COMMENT '禁用属性', 12 | `filter_order` varchar(45) DEFAULT NULL COMMENT '顺序', 13 | `application_name` varchar(45) DEFAULT NULL COMMENT '应用名称', 14 | PRIMARY KEY (`id`) 15 | ) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8; 16 | 17 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-logback-prod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %date [%thread] %-5level %logger{80}- %msg%n 10 | 11 | 12 | 13 | 14 | 15 | ${LOG_DIR}/${LOG_FILE_NAME} 16 | 17 | 18 | ${LOG_DIR}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i 19 | 21 | 22 | 100MB 23 | 24 | 30 25 | 26 | 27 | %date [%-5thread] %-5level [%-10logger] %-10msg%n 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %date [%thread] %-5level %logger{80}- %msg%n 10 | 11 | 12 | 13 | 14 | 15 | ${LOG_DIR}/${LOG_FILE_NAME} 16 | 17 | 18 | ${LOG_DIR}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i 19 | 21 | 22 | 100MB 23 | 24 | 30 25 | 26 | 27 | %date [%-5thread] %-5level [%-10logger] %-10msg%n 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-logback-uat.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %date [%thread] %-5level %logger{80}- %msg%n 10 | 11 | 12 | 13 | 14 | 15 | ${LOG_DIR}/${LOG_FILE_NAME} 16 | 17 | 18 | ${LOG_DIR}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i 19 | 21 | 22 | 100MB 23 | 24 | 30 25 | 26 | 27 | %date [%-5thread] %-5level [%-10logger] %-10msg%n 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %date [%thread] %-5level %logger{80}- %msg%n 10 | 11 | 12 | 13 | 14 | 15 | ${LOG_DIR}/${LOG_FILE_NAME} 16 | 17 | 18 | ${LOG_DIR}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i 19 | 21 | 22 | 100MB 23 | 24 | 30 25 | 26 | 27 | %date [%-5thread] %-5level [%-10logger] %-10msg%n 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-prod.properties: -------------------------------------------------------------------------------- 1 | ############################################# 2 | ###### Spring2go Zuul Configuration ###### 3 | ############################################# 4 | 5 | zuul.debug.request=false 6 | zuul.debug.parameter=debugRequest 7 | 8 | zuul.filter.pre.path=/opt/app/zuul/scripts/pre 9 | zuul.filter.route.path=/opt/app/zuul/scripts/route 10 | zuul.filter.post.path=/opt/app/zuul/scripts/post 11 | zuul.filter.error.path=/opt/app/zuul/scripts/error 12 | #zuul.filter.repository=http://192.168.100.133:8089/filters 13 | ############################################# 14 | ###### Filters Dao Source ###### 15 | ############################################# 16 | zuul.filter.poller.enabled=true 17 | zuul.filter.poller.interval=30000 18 | zuul.filter.table.name=zuul_filter 19 | zuul.data-source.class-name=com.mysql.jdbc.jdbc2.optional.MysqlDataSource 20 | zuul.data-source.url=jdbc:mysql://192.168.100.107:3306/spring2go_zuul_filter 21 | zuul.data-source.user=root 22 | zuul.data-source.password=mysql 23 | zuul.data-source.min-pool-size=10 24 | zuul.data-source.max-pool-size=20 25 | zuul.data-source.connection-timeout=1000 26 | zuul.data-source.idle-timeout=600000 27 | zuul.data-source.max-lifetime=1800000 28 | ############################################# 29 | 30 | 31 | ############################################# 32 | ###### Eureka Configuration ###### 33 | ############################################# 34 | eureka.region=default 35 | eureka.name=MobileZuul 36 | #should be the same as web server port 37 | eureka.port=8080 38 | eureka.vipAddress=mobile_zuul.spring2go.com 39 | eureka.preferSameZone=false 40 | eureka.shouldUseDns=false 41 | eureka.serviceUrl.default=http://eureka.spring2go.com/eureka/ 42 | eureka.default.availabilityZones=default 43 | eureka.asgName=MobileZuul 44 | ############################################# 45 | 46 | 47 | ############################################# 48 | ###### Hystrix ###### 49 | ############################################# 50 | hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=100 51 | 52 | hystrix.threadpool.default.coreSize=10 53 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=15000 54 | 55 | hystrix.command.default.circuitBreaker.enabled=true 56 | hystrix.command.default.circuitBreaker.forceOpen=false 57 | hystrix.command.default.circuitBreaker.forceClosed=false 58 | hystrix.command.default.circuitBreaker.requestVolumeThreshold=10 59 | hystrix.command.default.circuitBreaker.errorThresholdPercentage=30 60 | hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000 61 | ############################################# 62 | 63 | 64 | # TO BE ADDED 65 | 66 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-test.properties: -------------------------------------------------------------------------------- 1 | ############################################# 2 | ###### Spring2go Zuul Configuration ###### 3 | ############################################# 4 | 5 | zuul.debug.request=false 6 | zuul.debug.parameter=debugRequest 7 | 8 | #zuul.filter.pre.path=/opt/app/zuul/scripts/pre 9 | #zuul.filter.route.path=/opt/app/zuul/scripts/route 10 | #zuul.filter.post.path=/opt/app/zuul/scripts/post 11 | #zuul.filter.error.path=/opt/app/zuul/scripts/error 12 | #zuul.filter.repository=http://172.17.2.124:80/filters 13 | ############################################# 14 | ###### Filters Dao Source ###### 15 | ############################################# 16 | zuul.filter.poller.enabled=true 17 | zuul.filter.poller.interval=30000 18 | ############################################# 19 | 20 | 21 | ############################################# 22 | ###### Eureka Configuration ###### 23 | ############################################# 24 | eureka.region=default 25 | eureka.name=MoibleZuul 26 | #should be the same as web server port 27 | eureka.port=1113 28 | eureka.vipAddress=mobile_zuul.spring2go.com 29 | eureka.preferSameZone=false 30 | eureka.shouldUseDns=false 31 | eureka.serviceUrl.default=http://192.168.100.120:1113/eureka/,http://192.168.100.121:1113/eureka/,http://192.168.100.122:1113/eureka/ 32 | eureka.default.availabilityZones=default 33 | eureka.asgName=MobileZuul 34 | ############################################# 35 | 36 | 37 | ############################################# 38 | ###### Hystrix ###### 39 | ############################################# 40 | hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=100 41 | 42 | hystrix.threadpool.default.coreSize=10 43 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1500 44 | 45 | hystrix.command.default.circuitBreaker.enabled=true 46 | hystrix.command.default.circuitBreaker.forceOpen=false 47 | hystrix.command.default.circuitBreaker.forceClosed=false 48 | hystrix.command.default.circuitBreaker.requestVolumeThreshold=10 49 | hystrix.command.default.circuitBreaker.errorThresholdPercentage=30 50 | hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000 51 | ############################################# 52 | 53 | 54 | ############################################# 55 | ###### Custom Route ###### 56 | ############################################# 57 | 58 | ## TO BE ADDED 59 | 60 | #zuul.use.canary.filters=true -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul-uat.properties: -------------------------------------------------------------------------------- 1 | ############################################# 2 | ###### Spring2go Zuul Configuration ###### 3 | ############################################# 4 | 5 | zuul.debug.request=false 6 | zuul.debug.parameter=debugRequest 7 | 8 | zuul.filter.pre.path=/opt/app/zuul/scripts/pre 9 | zuul.filter.route.path=/opt/app/zuul/scripts/route 10 | zuul.filter.post.path=/opt/app/zuul/scripts/post 11 | zuul.filter.error.path=/opt/app/zuul/scripts/error 12 | #zuul.filter.repository=http://192.168.100.133:8088/filters 13 | ############################################# 14 | ###### Filters Dao Source ###### 15 | ############################################# 16 | zuul.filter.poller.enabled=true 17 | zuul.filter.poller.interval=30000 18 | zuul.filter.table.name=zuul_filter 19 | zuul.data-source.class-name=com.mysql.jdbc.jdbc2.optional.MysqlDataSource 20 | zuul.data-source.url=jdbc:mysql://192.168.100.120:3306/spring2go_zuul_filter 21 | zuul.data-source.user=root 22 | zuul.data-source.password=mysql 23 | zuul.data-source.min-pool-size=10 24 | zuul.data-source.max-pool-size=20 25 | zuul.data-source.connection-timeout=1000 26 | zuul.data-source.idle-timeout=600000 27 | zuul.data-source.max-lifetime=1800000 28 | ############################################# 29 | 30 | 31 | ############################################# 32 | ###### Eureka Configuration ###### 33 | ############################################# 34 | eureka.region=default 35 | eureka.name=MobileZuul 36 | #should be the same as web server port 37 | eureka.port=8080 38 | eureka.vipAddress=mobile_zuul.spring2go.com 39 | eureka.preferSameZone=false 40 | eureka.shouldUseDns=false 41 | eureka.serviceUrl.default=http://uat-eureka.spring2go.com/eureka/ 42 | eureka.default.availabilityZones=default 43 | eureka.asgName=MobileZuul 44 | ############################################# 45 | 46 | 47 | ############################################# 48 | ###### Hystrix ###### 49 | ############################################# 50 | hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=100 51 | 52 | hystrix.threadpool.default.coreSize=10 53 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=15000 54 | 55 | hystrix.command.default.circuitBreaker.enabled=true 56 | hystrix.command.default.circuitBreaker.forceOpen=false 57 | hystrix.command.default.circuitBreaker.forceClosed=false 58 | hystrix.command.default.circuitBreaker.requestVolumeThreshold=10 59 | hystrix.command.default.circuitBreaker.errorThresholdPercentage=30 60 | hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000 61 | ############################################# 62 | 63 | 64 | ############################################# 65 | ###### Custom Route ###### 66 | ############################################# 67 | 68 | # TO BE ADDED 69 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/resources/mobile_zuul.properties: -------------------------------------------------------------------------------- 1 | ############################################# 2 | ###### Spring2go Zuul Configuration ###### 3 | ############################################# 4 | 5 | zuul.debug.request=true 6 | zuul.debug.parameter=debugRequest 7 | #zuul.include.debug.header=true 8 | zuul.filter.dao.type=jdbc 9 | archaius.deployment.applicationId=mobile_zuul 10 | #zuul.filter.repository=http://192.168.100.106:80/filters 11 | zuul.filter.pre.path=D:/temp/scripts/pre 12 | zuul.filter.route.path=D:/temp/scripts/route 13 | zuul.filter.post.path=D:/temp/scripts/post 14 | zuul.filter.error.path=D:/temp/scripts/error 15 | ############################################# 16 | 17 | 18 | ############################################# 19 | ###### Filters Dao Source ###### 20 | ############################################# 21 | zuul.filter.poller.enabled=true 22 | zuul.filter.poller.interval=30000 23 | zuul.filter.table.name=zuul_filter 24 | zuul.data-source.class-name=com.mysql.jdbc.jdbc2.optional.MysqlDataSource 25 | zuul.data-source.url=jdbc:mysql://localhost:3306/spring2go_zuul_filter 26 | zuul.data-source.user=root 27 | zuul.data-source.password=mysql 28 | zuul.data-source.min-pool-size=10 29 | zuul.data-source.max-pool-size=20 30 | zuul.data-source.connection-timeout=1000 31 | zuul.data-source.idle-timeout=600000 32 | zuul.data-source.max-lifetime=1800000 33 | ############################################# 34 | 35 | 36 | ############################################# 37 | ###### Eureka Configuration ###### 38 | ############################################# 39 | eureka.enabled=false 40 | eureka.region=default 41 | eureka.name=MobileZuul 42 | #should be the same as web server port 43 | eureka.port=1113 44 | eureka.vipAddress=mobile_zuul.spring2go.com 45 | eureka.preferSameZone=false 46 | eureka.shouldUseDns=false 47 | eureka.serviceUrl.default=http://192.168.100.120:1113/eureka/,http://192.168.100.121:1113/eureka/,http://192.168.100.122:1113/eureka/ 48 | eureka.default.availabilityZones=default 49 | eureka.asgName=MobileZuul 50 | ############################################# 51 | 52 | 53 | ############################################# 54 | ###### Hystrix ###### 55 | ############################################# 56 | hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=100 57 | hystrix.threadpool.default.coreSize=10 58 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1500 59 | hystrix.command.default.circuitBreaker.enabled=true 60 | hystrix.command.default.circuitBreaker.forceOpen=false 61 | hystrix.command.default.circuitBreaker.forceClosed=false 62 | hystrix.command.default.circuitBreaker.requestVolumeThreshold=10 63 | hystrix.command.default.circuitBreaker.errorThresholdPercentage=30 64 | hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000 65 | ############################################# 66 | 67 | ############################################# 68 | ###### Custom Route ###### 69 | ############################################# 70 | 71 | # TO BE ADDED 72 | zuul.routing_table_string=student@http://localhost:9700&hello@http://localhost:9700 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | zuul-gateway 7 | 8 | 9 | AsyncZuulServlet 10 | io.spring2go.zuul.servlet.AsyncZuulServlet 11 | true 12 | 13 | 14 | AsyncZuulServlet 15 | /* 16 | 17 | 18 | 19 | io.spring2go.zuul.servlet.InitializeServletListener 20 | 21 | 22 | 23 | CatFilter 24 | io.spring2go.zuul.servlet.CatServletFilter 25 | 26 | 27 | CatFilter 28 | /* 29 | 30 | 31 | 32 | scriptManager 33 | io.spring2go.zuul.filters.FilterScriptManagerServlet 34 | 35 | 36 | scriptManager 37 | /admin/scriptmanager 38 | 39 | 40 | 41 | filterLoader 42 | /admin/filterLoader.jsp 43 | 44 | 45 | filterLoader 46 | /admin/filterLoader.jsp 47 | 48 | 49 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/error/ErrorResponse.groovy: -------------------------------------------------------------------------------- 1 | package scripts.error 2 | 3 | import org.slf4j.Logger 4 | import org.slf4j.LoggerFactory 5 | 6 | import io.spring2go.zuul.common.ZuulException 7 | import io.spring2go.zuul.context.RequestContext 8 | import io.spring2go.zuul.filters.ZuulFilter 9 | 10 | /** 11 | * Generate a error response while there is an error. 12 | */ 13 | class ErrorResponse extends ZuulFilter { 14 | private static final Logger logger = LoggerFactory.getLogger(this.getClass()) 15 | 16 | @Override 17 | String filterType() { 18 | return 'error' 19 | } 20 | 21 | @Override 22 | int filterOrder() { 23 | return 10 24 | } 25 | 26 | @Override 27 | boolean shouldFilter() { 28 | def context = RequestContext.getCurrentContext() 29 | return context.getThrowable() != null && !context.errorHandled() 30 | } 31 | 32 | 33 | @Override 34 | Object run() { 35 | RequestContext ctx = RequestContext.getCurrentContext(); 36 | Throwable ex = ctx.getThrowable() 37 | try { 38 | String errorCause="Zuul-Error-Unknown-Cause"; 39 | int responseStatusCode; 40 | 41 | if (ex instanceof ZuulException) { 42 | String cause = ex.errorCause 43 | if(cause!=null) errorCause = cause; 44 | responseStatusCode = ex.nStatusCode; 45 | 46 | Enumeration headerIt = ctx.getRequest().getHeaderNames(); 47 | StringBuilder sb = new StringBuilder(ctx.getRequest().getRequestURI()+":"+errorCause); 48 | while (headerIt.hasMoreElements()) { 49 | String name = (String) headerIt.nextElement(); 50 | String value = ctx.getRequest().getHeader(name); 51 | sb.append("REQUEST:: > " + name + ":" + value+"\n"); 52 | } 53 | logger.error(sb.toString()); 54 | }else{ 55 | responseStatusCode = 500; 56 | } 57 | 58 | ctx.setResponseStatusCode(responseStatusCode); 59 | 60 | 61 | ctx.addZuulResponseHeader("Content-Type", "application/json; charset=utf-8"); 62 | ctx.setSendZuulResponse(false) 63 | ctx.setResponseBody("{\"Message\":\""+errorCause+"\"}"); 64 | } finally { 65 | ctx.setErrorHandled(true) //ErrorResponse was handled 66 | return null; 67 | } 68 | } 69 | 70 | 71 | 72 | 73 | 74 | 75 | } -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/post/AddTimeStamp.groovy: -------------------------------------------------------------------------------- 1 | package scripts.post 2 | 3 | import io.spring2go.zuul.common.ZuulException; 4 | import io.spring2go.zuul.context.RequestContext; 5 | import io.spring2go.zuul.filters.ZuulFilter; 6 | 7 | public class AddTimeStamp extends ZuulFilter { 8 | 9 | private final static int TIMESTAMP_EXPIRED_SECS = 600; 10 | 11 | @Override 12 | public String filterType() { 13 | return "post"; 14 | } 15 | 16 | @Override 17 | public boolean shouldFilter() { 18 | return true; 19 | } 20 | @Override 21 | public int filterOrder() { 22 | return 1; 23 | 24 | } 25 | @Override 26 | public Object run() throws ZuulException { 27 | long time = System.currentTimeMillis()/1000; 28 | RequestContext.getCurrentContext().addZuulResponseHeader("X-S2G-TIMESTAMP", String.valueOf(time)); 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/post/DebugHeader.groovy: -------------------------------------------------------------------------------- 1 | package scripts.post 2 | 3 | import javax.servlet.http.HttpServletRequest 4 | import javax.servlet.http.HttpServletResponse 5 | 6 | import com.netflix.config.DynamicBooleanProperty 7 | import com.netflix.config.DynamicPropertyFactory 8 | import com.netflix.util.Pair 9 | import io.spring2go.zuul.context.RequestContext 10 | import io.spring2go.zuul.filters.ZuulFilter 11 | 12 | 13 | class DebugHeader extends ZuulFilter { 14 | static final DynamicBooleanProperty INCLUDE_DEBUG_HEADER = 15 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.include.debug.header", false); 16 | 17 | static final DynamicBooleanProperty INCLUDE_ROUTE_URL_HEADER = 18 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.include-route-url-header", true); 19 | 20 | @Override 21 | String filterType() { 22 | return 'post' 23 | } 24 | 25 | @Override 26 | int filterOrder() { 27 | return 10 28 | } 29 | 30 | @Override 31 | boolean shouldFilter() { 32 | return INCLUDE_DEBUG_HEADER.get(); 33 | } 34 | 35 | @Override 36 | Object run() { 37 | addStandardResponseHeaders(RequestContext.getCurrentContext().getRequest(), RequestContext.getCurrentContext().getResponse()) 38 | return null; 39 | } 40 | 41 | void addStandardResponseHeaders(HttpServletRequest req, HttpServletResponse res) { 42 | 43 | RequestContext context = RequestContext.getCurrentContext() 44 | List> headers = context.getZuulResponseHeaders() 45 | headers.add(new Pair("X_ZUUL", "mobile_gateway")) 46 | // TODO, get zuul instance id 47 | headers.add(new Pair("CONNECTION", "KEEP_ALIVE")) 48 | headers.add(new Pair("X_ZUUL_FILTER_EXECUTION_STATUS", context.getFilterExecutionSummary().toString())) 49 | headers.add(new Pair("X_ORIGINATING_URL", originatingURL)) 50 | if (INCLUDE_ROUTE_URL_HEADER.get()) { 51 | String routeUrl = context.getRouteUrl(); 52 | if (routeUrl != null && !routeUrl.empty) { 53 | headers.add(new Pair("x-zuul-route-url", routeUrl)); 54 | } 55 | } 56 | 57 | //Support CORS 58 | headers.add(new Pair("Access-Control-Allow-Origin", "*")) 59 | headers.add(new Pair("Access-Control-Allow-Headers","Content-Type, Accept")) 60 | 61 | headers.add(new Pair("x-zuul-remote-call-cost", String.valueOf(RequestContext.getCurrentContext().get("remoteCallCost")))) 62 | 63 | if (!context.errorHandled() && context.responseStatusCode >= 400) { 64 | headers.add(new Pair("X_ZUUL_ERROR_CAUSE", "Error from Origin")) 65 | 66 | } 67 | 68 | if (INCLUDE_DEBUG_HEADER.get()) { 69 | String debugHeader = ""; 70 | List rd = (List) context.get("routingDebug"); 71 | rd?.each { debugHeader += "[[[${it}]]]"; } 72 | 73 | headers.add(new Pair("X-Zuul-Debug-Header", debugHeader)); 74 | } 75 | } 76 | 77 | String getOriginatingURL() { 78 | HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); 79 | 80 | String protocol = request.getHeader("X_FORWARDED_PROTO") 81 | if (protocol == null) protocol = "http" 82 | String host = request.getHeader("HOST") 83 | String uri = request.getRequestURI(); 84 | def URL = "${protocol}://${host}${uri}" 85 | if (request.getQueryString() != null) { 86 | URL += "?${request.getQueryString()}" 87 | } 88 | return URL 89 | } 90 | 91 | 92 | } 93 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/post/DebugResponse.groovy: -------------------------------------------------------------------------------- 1 | package scripts.post 2 | 3 | import org.slf4j.Logger 4 | import org.slf4j.LoggerFactory 5 | 6 | import com.netflix.config.DynamicBooleanProperty 7 | import com.netflix.config.DynamicPropertyFactory 8 | import com.netflix.util.Pair 9 | import io.spring2go.zuul.context.RequestContext 10 | import io.spring2go.zuul.filters.ZuulFilter 11 | import io.spring2go.zuul.util.Debug 12 | 13 | class DebugResponse extends ZuulFilter { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(DebugResponse.class); 15 | 16 | private static final String ZUUL_BODY_DEBUG_DISABLE = "zuul.body.debug.disable"; 17 | private static final String ZUUL_HEADER_DEBUG_DISABLE = "zuul.header.debug.disable"; 18 | static final DynamicBooleanProperty BODY_DEBUG_DISABLED = 19 | DynamicPropertyFactory.getInstance().getBooleanProperty(ZUUL_BODY_DEBUG_DISABLE, false); 20 | static final DynamicBooleanProperty HEADER_DEBUG_DISABLED = 21 | DynamicPropertyFactory.getInstance().getBooleanProperty(ZUUL_HEADER_DEBUG_DISABLE, true); 22 | 23 | @Override 24 | String filterType() { 25 | return 'post' 26 | } 27 | 28 | @Override 29 | int filterOrder() { 30 | return 1000 31 | } 32 | 33 | @Override 34 | boolean shouldFilter() { 35 | return Debug.debugRequest(); 36 | } 37 | 38 | @Override 39 | Object run() { 40 | RequestContext.getCurrentContext().getZuulResponseHeaders()?.each { Pair it -> 41 | Debug.addRequestDebug("OUTBOUND: < " + it.first() + ":" + it.second()) 42 | } 43 | dumpRoutingDebug() 44 | dumpRequestDebug() 45 | return null; 46 | } 47 | 48 | public void dumpRequestDebug() { 49 | List rd = (List) RequestContext.getCurrentContext().get("requestDebug"); 50 | StringBuilder b = new StringBuilder(""); 51 | rd?.each { 52 | b.append("REQUEST_DEBUG::${it}\n"); 53 | } 54 | LOGGER.info(b.toString()); 55 | } 56 | 57 | public void dumpRoutingDebug() { 58 | List rd = (List) RequestContext.getCurrentContext().get("routingDebug"); 59 | StringBuilder b = new StringBuilder(""); 60 | rd?.each { 61 | b.append("ZUUL_DEBUG::${it}\n"); 62 | } 63 | LOGGER.info(b.toString()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/post/Stats.groovy: -------------------------------------------------------------------------------- 1 | package scripts.post 2 | 3 | import io.spring2go.zuul.context.RequestContext 4 | import io.spring2go.zuul.filters.ZuulFilter 5 | import io.spring2go.zuul.monitor.StatManager 6 | 7 | class Stats extends ZuulFilter { 8 | @Override 9 | String filterType() { 10 | return "post" 11 | } 12 | 13 | @Override 14 | int filterOrder() { 15 | return 20000 16 | } 17 | 18 | @Override 19 | boolean shouldFilter() { 20 | return true 21 | } 22 | 23 | @Override 24 | Object run() { 25 | RequestContext ctx = RequestContext.getCurrentContext(); 26 | int status = ctx.getResponseStatusCode(); 27 | StatManager sm = StatManager.manager 28 | sm.collectRequestStats(ctx.getRequest()); 29 | sm.collectRouteStatusStats(ctx.routeName, status); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/pre/DebugModeSetter.groovy: -------------------------------------------------------------------------------- 1 | package scripts.pre 2 | 3 | import com.netflix.config.DynamicBooleanProperty 4 | import com.netflix.config.DynamicPropertyFactory 5 | import com.netflix.config.DynamicStringProperty 6 | import io.spring2go.zuul.context.RequestContext 7 | import io.spring2go.zuul.filters.ZuulFilter 8 | 9 | class DebugModeSetter extends ZuulFilter { 10 | 11 | static final DynamicBooleanProperty couldSetDebug = 12 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.could.set.debug", true); 13 | static final DynamicBooleanProperty debugRequest = 14 | DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.debug.request", false); 15 | static final DynamicStringProperty debugParameter = 16 | DynamicPropertyFactory.getInstance().getStringProperty("zuul.debug.parameter", "debugRequest"); 17 | 18 | @Override 19 | String filterType() { 20 | return 'pre' 21 | } 22 | 23 | @Override 24 | int filterOrder() { 25 | return -100; 26 | } 27 | 28 | boolean shouldFilter() { 29 | if (!couldSetDebug.get()) { 30 | return false 31 | } 32 | if ("true".equals(RequestContext.currentContext.getRequest().getParameter(debugParameter.get()))) return true; 33 | return debugRequest.get(); 34 | } 35 | 36 | Object run() { 37 | RequestContext.getCurrentContext().setDebugRequest(true) 38 | RequestContext.getCurrentContext().setDebugRouting(true) 39 | return null; 40 | } 41 | } 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/pre/DebugRequest.groovy: -------------------------------------------------------------------------------- 1 | package scripts.pre 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import com.dianping.cat.Cat 6 | import com.dianping.cat.message.Transaction 7 | import com.netflix.config.DynamicBooleanProperty; 8 | import com.netflix.config.DynamicPropertyFactory; 9 | import io.spring2go.zuul.context.RequestContext; 10 | import io.spring2go.zuul.filters.ZuulFilter; 11 | import io.spring2go.zuul.util.Debug; 12 | 13 | public class DebugRequest extends ZuulFilter { 14 | 15 | private static final DynamicBooleanProperty BODY_DEBUG_DISABLED = DynamicPropertyFactory.getInstance().getBooleanProperty("zuul.body.debug.disable", false); 16 | 17 | 18 | @Override 19 | public String filterType() { 20 | return "pre"; 21 | } 22 | 23 | @Override 24 | public int filterOrder() { 25 | return -10; 26 | } 27 | 28 | @Override 29 | public boolean shouldFilter() { 30 | return Debug.debugRequest(); 31 | } 32 | 33 | @Override 34 | public Object run() { 35 | 36 | RequestContext ctx = RequestContext.getCurrentContext() 37 | Transaction tran = Cat.getProducer().newTransaction("DebugRequestFilter", ctx.getRequest().getRequestURL().toString()); 38 | 39 | try { 40 | HttpServletRequest req = ctx.getRequest(); 41 | 42 | Debug.addRequestDebug("REQUEST:: " + req.getScheme() + " " + req.getRemoteAddr() + ":" + req.getRemotePort()); 43 | Debug.addRequestDebug("REQUEST:: > " + req.getMethod() + " " + req.getRequestURI() + " " + req.getProtocol()); 44 | 45 | Enumeration headerIt = req.getHeaderNames(); 46 | while (headerIt.hasMoreElements()) { 47 | String name = (String) headerIt.nextElement(); 48 | String value = req.getHeader(name); 49 | Debug.addRequestDebug("REQUEST:: > " + name + ":" + value); 50 | } 51 | 52 | 53 | if (!ctx.isChunkedRequestBody() && !BODY_DEBUG_DISABLED.get()) { 54 | InputStream inp = ctx.getRequest().getInputStream(); 55 | String body = null; 56 | if (inp != null) { 57 | body = inp.getText(); 58 | Debug.addRequestDebug("REQUEST:: > " + body); 59 | } 60 | } 61 | tran.setStatus(Transaction.SUCCESS); 62 | } catch (Throwable e) { 63 | tran.setStatus(e); 64 | throw e; 65 | } finally { 66 | tran.complete(); 67 | } 68 | return null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/pre/HealthCheck.groovy: -------------------------------------------------------------------------------- 1 | package scripts.pre 2 | 3 | import javax.servlet.http.HttpServletResponse 4 | 5 | import com.netflix.config.DynamicBooleanProperty 6 | import com.netflix.config.DynamicPropertyFactory 7 | import io.spring2go.zuul.context.RequestContext 8 | import io.spring2go.zuul.filters.ZuulFilter 9 | 10 | public class HealthCheck extends ZuulFilter{ 11 | @Override 12 | public String filterType() { 13 | return "pre"; 14 | } 15 | 16 | public Object uri() { 17 | return "/healthcheck"; 18 | } 19 | 20 | @Override 21 | boolean shouldFilter() { 22 | String path = RequestContext.currentContext.getRequest().getRequestURI() 23 | return path.equalsIgnoreCase(uri())||path.toLowerCase().endsWith(uri()); 24 | } 25 | 26 | public int filterOrder(){ 27 | return 0; 28 | } 29 | 30 | public String responseBody() { 31 | return "ok"; 32 | } 33 | 34 | @Override 35 | Object run() { 36 | RequestContext ctx = RequestContext.getCurrentContext(); 37 | // Set the default response code for static filters to be 200 38 | ctx.getResponse().setStatus(HttpServletResponse.SC_OK); 39 | ctx.getResponse().setContentType('application/xml') 40 | // first StaticResponseFilter instance to match wins, others do not set body and/or status 41 | if (ctx.getResponseBody() == null) { 42 | ctx.setResponseBody(responseBody()) 43 | ctx.sendZuulResponse = false; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /s2g-zuul-mobile/src/scripts/pre/TestRoute.groovy: -------------------------------------------------------------------------------- 1 | package io.spring2go.zuul.mobile; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | import java.util.HashMap; 6 | import java.util.concurrent.atomic.AtomicReference; 7 | 8 | import org.apache.commons.lang.StringUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import com.netflix.config.DynamicPropertyFactory; 13 | import com.netflix.config.DynamicStringProperty; 14 | 15 | import io.spring2go.zuul.common.ZuulException; 16 | import io.spring2go.zuul.context.RequestContext; 17 | import io.spring2go.zuul.filters.ZuulFilter; 18 | 19 | public class TestRouting extends ZuulFilter { 20 | 21 | private static Logger logger = LoggerFactory.getLogger(TestRouting.class); 22 | 23 | private static final AtomicReference> routingTableRef = new AtomicReference>(); 24 | 25 | private static final DynamicStringProperty ROUTING_TABLE_STRING_PROPERTY = DynamicPropertyFactory.getInstance() 26 | .getStringProperty("zuul.routing_table_string", null); 27 | 28 | static { 29 | buildRoutingTable(); 30 | 31 | ROUTING_TABLE_STRING_PROPERTY.addCallback(new Runnable() { 32 | 33 | @Override 34 | public void run() { 35 | buildRoutingTable(); 36 | } 37 | 38 | }); 39 | } 40 | 41 | static void buildRoutingTable() { 42 | logger.info("building routing table"); 43 | HashMap routingTable = new HashMap(); 44 | String routingTableString = ROUTING_TABLE_STRING_PROPERTY.get(); 45 | if (StringUtils.isEmpty(routingTableString)) { 46 | logger.warn("routing table string is empty, nothing to build"); 47 | return; 48 | } 49 | String[] routingEntries = routingTableString.split("&"); 50 | for (String routingEntry : routingEntries) { 51 | String[] kvs = routingEntry.split("@"); 52 | if (kvs.length == 2) { 53 | String svcName = kvs[0]; 54 | String urlString = kvs[1]; 55 | routingTable.put(svcName, urlString); 56 | logger.info("added route entry key = " + svcName + ", value = " + urlString); 57 | } 58 | } 59 | if (routingTable.size() > 0) { 60 | routingTableRef.set(routingTable); 61 | logger.info("routing table updated, entry size " + routingTable.size()); 62 | } else { 63 | logger.info("routing table is not updated, entry size is 0"); 64 | } 65 | } 66 | 67 | @Override 68 | public boolean shouldFilter() { 69 | RequestContext ctx = RequestContext.getCurrentContext(); 70 | return ctx.sendZuulResponse(); 71 | } 72 | 73 | // sample url 74 | // http://api.spring2go.com/api/hello 75 | @Override 76 | public Object run() throws ZuulException { 77 | RequestContext ctx = RequestContext.getCurrentContext(); 78 | String path = ctx.getRequest().getRequestURI(); 79 | String requestPath = ""; 80 | String serviceName = ""; 81 | String requestMethod = ""; 82 | int index = path.lastIndexOf("/api/"); 83 | if (index > 0) { 84 | requestPath = path.substring(index + 5); 85 | if (StringUtils.isNotEmpty(requestPath)) { 86 | int index2 = requestPath.indexOf("/"); 87 | if (index2 > 0) { 88 | serviceName = requestPath.substring(0, index2); 89 | requestMethod = requestPath.substring(index2 + 1); 90 | } else { 91 | serviceName = requestPath; 92 | } 93 | } 94 | } 95 | if (StringUtils.isNotEmpty(serviceName)) { 96 | String urlString = routingTableRef.get().get(serviceName); 97 | if (StringUtils.isNotEmpty(urlString)) { 98 | if (StringUtils.isNotEmpty(requestMethod)) { 99 | urlString = urlString.endsWith("/") ? urlString + requestMethod : urlString + "/" + requestMethod; 100 | } 101 | URL url; 102 | try { 103 | url = new URL(urlString); 104 | ctx.setRouteUrl(url); 105 | } catch (MalformedURLException e) { 106 | throw new ZuulException(e, "Malformed URL exception", 500, "Malformed URL exception"); 107 | } 108 | } 109 | } 110 | 111 | if (ctx.getRouteUrl() == null) { 112 | throw new ZuulException("No route found", 404, "No route found"); 113 | } 114 | 115 | return null; 116 | } 117 | 118 | @Override 119 | public String filterType() { 120 | return "pre"; 121 | } 122 | 123 | @Override 124 | public int filterOrder() { 125 | return 20; 126 | } 127 | 128 | } 129 | --------------------------------------------------------------------------------