├── .gitignore ├── LICENSE.txt ├── README.md ├── core ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── bj58 │ │ └── argo │ │ ├── ActionResult.java │ │ ├── Argo.java │ │ ├── ArgoController.java │ │ ├── ArgoException.java │ │ ├── BeatContext.java │ │ ├── Model.java │ │ ├── annotations │ │ ├── GET.java │ │ ├── POST.java │ │ └── Path.java │ │ ├── client │ │ ├── ClientContext.java │ │ ├── Cookies.java │ │ ├── SafeParameter.java │ │ └── Upload.java │ │ ├── controller │ │ ├── AbstractController.java │ │ ├── ReverseProxy.java │ │ └── ViewFactory.java │ │ ├── convention │ │ ├── EmptyModule.java │ │ ├── GroupConvention.java │ │ ├── GroupConventionAnnotation.java │ │ ├── GroupConventionFactory.java │ │ ├── GroupConventionUtils.java │ │ └── ProjectConvention.java │ │ ├── inject │ │ ├── ArgoModule.java │ │ └── ArgoSystem.java │ │ ├── interceptor │ │ ├── ExceptInterceptor.java │ │ ├── PostInterceptor.java │ │ ├── PostInterceptorAnnotation.java │ │ ├── PreInterceptor.java │ │ └── PreInterceptorAnnotation.java │ │ ├── internal │ │ ├── ActionInfo.java │ │ ├── BeatContextWrapper.java │ │ ├── ControllerInfo.java │ │ ├── DefaultArgoDispatcher.java │ │ ├── DefaultBeatContext.java │ │ ├── DefaultGroupConvention.java │ │ ├── DefaultLogger.java │ │ ├── DefaultLoggerFactory.java │ │ ├── DefaultModel.java │ │ ├── DefaultMultipartConfigElementProvider.java │ │ ├── DefaultRouter.java │ │ ├── MethodAction.java │ │ ├── OldArgoRequest.java │ │ ├── StaticFilesAction.java │ │ ├── VelocityViewFactory.java │ │ └── actionresult │ │ │ ├── StaticActionResult.java │ │ │ ├── StatusCodeActionResult.java │ │ │ └── statuscode │ │ │ └── ActionResults.java │ │ ├── lifecycle │ │ ├── LifeCycleState.java │ │ ├── Lifecycle.java │ │ ├── LifecycleEvent.java │ │ └── LifecycleEventsManager.java │ │ ├── logs │ │ ├── LogConfigure.java │ │ ├── Logger.java │ │ └── LoggerFactory.java │ │ ├── route │ │ ├── Action.java │ │ ├── RouteBag.java │ │ ├── RouteResult.java │ │ ├── Router.java │ │ └── StaticActionAnnotation.java │ │ ├── servlet │ │ ├── ArgoDispatcher.java │ │ ├── ArgoDispatcherFactory.java │ │ ├── ArgoFilter.java │ │ └── ArgoRequest.java │ │ ├── thirdparty │ │ ├── AnnotationUtils.java │ │ ├── AntPathMatcher.java │ │ ├── AntPathStringMatcher.java │ │ ├── BridgeMethodResolver.java │ │ ├── ClassUtil.java │ │ ├── Collections.java │ │ ├── GenericTypeResolver.java │ │ ├── HttpUtils.java │ │ ├── PathMatcher.java │ │ ├── ReflectionUtils.java │ │ ├── StringUtil.java │ │ └── jetty │ │ │ ├── B64Code.java │ │ │ ├── ByteArrayOutputStream2.java │ │ │ ├── IO.java │ │ │ ├── JettyMultiPartRequestWrapper.java │ │ │ ├── LazyList.java │ │ │ ├── MultiException.java │ │ │ ├── MultiMap.java │ │ │ ├── MultiPartInputStreamParser.java │ │ │ ├── QuotedStringTokenizer.java │ │ │ ├── ReadLineInputStream.java │ │ │ ├── StringMap.java │ │ │ ├── StringUtil.java │ │ │ ├── TypeUtil.java │ │ │ ├── UrlEncoded.java │ │ │ ├── Utf8Appendable.java │ │ │ ├── Utf8StringBuffer.java │ │ │ └── Utf8StringBuilder.java │ │ └── utils │ │ ├── ClassUtils.java │ │ ├── NetUtils.java │ │ ├── OnlyOnceCondition.java │ │ ├── Pair.java │ │ ├── PathUtils.java │ │ ├── TouchTimer.java │ │ └── converter │ │ ├── BooleanConverter.java │ │ ├── ByteConverter.java │ │ ├── CharacterConverter.java │ │ ├── Converter.java │ │ ├── ConverterFactory.java │ │ ├── DoubleConverter.java │ │ ├── FloatConverter.java │ │ ├── IntegerConverter.java │ │ ├── LongConverter.java │ │ ├── ShortConverter.java │ │ ├── StringConverter.java │ │ └── package-info.java │ └── test │ └── java │ ├── com │ └── bj58 │ │ └── argo │ │ ├── ArgoDispatcherTest.java │ │ ├── ArgoExceptionTest.java │ │ ├── ArgoFilterTest.java │ │ ├── ArgoTest.java │ │ ├── HadesModuleTest.java │ │ ├── action │ │ └── ActionInfoTest.java │ │ ├── client │ │ └── IpAddressUtilTest.java │ │ ├── convention │ │ ├── DefaultGroupConventionTest.java │ │ └── GroupConventionAnnotationTest.java │ │ ├── learn │ │ ├── ClassTest.java │ │ ├── FileTest.java │ │ └── injector │ │ │ ├── InjectTest.java │ │ │ └── ProvidersTest.java │ │ ├── logs │ │ └── LoggerTest.java │ │ ├── route │ │ └── PathMatcherTest.java │ │ ├── test │ │ └── TestBeatContextProvider.java │ │ └── utils │ │ ├── OnlyOnceConditionTest.java │ │ └── PathUtilsTest.java │ └── learn │ ├── BeanScan.java │ ├── ExceptionTest.java │ ├── ExecuteLearn.java │ ├── FileTest.java │ ├── HashmapTest.java │ ├── InjectorLearn.java │ ├── LearnJssist.java │ ├── MapTest.java │ ├── MyClassLoader1.java │ ├── PokerTest.java │ └── guice │ └── LearnKey.java ├── plugin ├── BJ58-SPAT-Plugins_Argo_DOC.pdf └── com.bj58.spat.plugins.argo_1.0.0.jar ├── pom.xml └── samples ├── company ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ ├── bj58 │ │ └── argo │ │ │ └── GroupConventionBinder.java │ │ └── mycompany │ │ └── sample │ │ └── controllers │ │ └── HomeController.java │ ├── resources │ └── views │ │ └── hello.html │ └── webapp │ └── 1.html └── hello-world ├── pom.xml └── src └── main ├── java └── com │ └── bj58 │ └── argo │ └── controllers │ ├── HelloController.java │ └── HomeController.java ├── resources └── views │ ├── index.html │ ├── post-upload.html │ └── post.html └── webapp ├── 1.html ├── form.html └── upload-form.html /.gitignore: -------------------------------------------------------------------------------- 1 | /core/target 2 | /samples/company/target 3 | /samples/hello-world/target 4 | /*.project 5 | /core/* 6 | /core/*.classpath 7 | /core/*.project 8 | /samples/company/.settings 9 | /samples/company/bin 10 | /samples/company/.classpath 11 | /samples/company/.project 12 | /samples/hello-world/.settings 13 | /samples/hello-world/bin 14 | /samples/hello-world/.classpath 15 | /samples/hello-world/.project 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright Beijing 58 Information Technology Co.,Ltd. 2 | 3 | Licensed to the Apache Software Foundation (ASF) under one 4 | or more contributor license agreements. See the NOTICE file 5 | distributed with this work for additional information 6 | regarding copyright ownership. The ASF licenses this file 7 | to you under the Apache License, Version 2.0 (the 8 | "License"); you may not use this file except in compliance 9 | with the License. You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, 14 | software distributed under the License is distributed on an 15 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | KIND, either express or implied. See the License for the 17 | specific language governing permissions and limitations 18 | under the License. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 历史,动机(motivation) 2 | 3 | Argo起源与[58同城]的内部web框架wf(web framework)。 4 | 5 | 目前wf支撑着[58同城]几乎所有的web站点,包括wap和手机端的访问等,现在wf每天处理10亿级的请求。经过长时间的运作与运行,证明wf是一个可靠的、高效的web框架。 6 | 7 | 8 | 作为一个有一定规模的互联网企业,如果在变化的互联网环境中上线一个项目,在软件开发中需要在三方面进行平衡: 9 | 10 | 1. 组织/公司,在一个组织内部,需要每个项目开发尽量有统一的风格、架构,学习成本、维护成本等尽可能低; 11 | 1. 运维,希望每个站点的配置和可执行部分分离,部署的方式相同; 12 | 1. 项目内部,希望程序员聚焦在业务上,可以快速实现产品需求、响应产品变化。 13 | 在此基础上,我们开发了wf。 14 | 15 | Argo在wf做了大量优化和重构,以适应各组织软件开发的个性化需求,提升了系统性能,具有更好的可扩展性。Argo的开源反过来也促进wf2.0的开发。 16 | 17 | 18 | ## 哲学观 (philosophy) 19 | 1. [约定优于配置],减少软件开发人员需做决定的数量,获得简单的好处,而又不失灵活性。Argo体系中有且只有一个组织级约定,规定包的命名,配置文件路径,日志文件路径等。组织的约定是不容侵犯,每个项目在组织级约定下工作。组织级约定建议以jar形式下发给各项目。 20 | 1. 简单,Argo可以不需要任何配置文件,项目代码结构简单,易于维护。 21 | 1. 纪律,包和类的命名都受组织级约定的控制,任何违反约定的行为可能导致系统无法正常运行。 22 | 23 | ## 系统特点 (features) 24 | 25 | 1. SEO友好的URL结构,Argo天然支持RESTful的url结构,并能自动匹配合适的参数; 26 | 1. 零配置,甚至你不要web.xml就能在tomcat上运行; 27 | 1. 插拔式组件架构,可以灵活扩张功能; 28 | 1. 高安全性,提供集群模式下,避免ip欺骗等功能。 29 | 30 | ## 系统约定 (convention) 31 | 32 | Argo不是一个通用的web框架,一个问题解决方案可能有很多,但在Argo中只提供一种解决方案。Argo在以下约定中工作: 33 | 34 | 1. servlet 3.0环境,主要针对Tomcat 7.x; 35 | 1. 基于[guice]的Ioc,组织和项目可以各提供一个module注入模块,而且module的命名必须符合约定; 36 | 1. maven依赖,项目的代码体系和maven默认代码体系一致,maven以插件提供开发过程中所需要的开发运行环境([jetty:run]或[tomcat7:run])。 37 | 38 | ## Hello World 39 | 40 | 请参考例子 samples/hello-world 41 | 42 | ```shell 43 | mvn tomcat7:run 44 | ``` 45 | 46 | 或者 47 | ```shell 48 | mvn jetty:run 49 | ``` 50 | 51 | 然后浏览 52 | 53 | http://localhost/ 54 | 55 | ## 进阶 56 | 57 | TODO 58 | 59 | ## 如何实现 (how) 60 | 61 | TODO 62 | 63 | ## 更新日志 64 | ### 2013-03-21 65 | 1. 修正 issues #1, #2, 66 | 1. 修正 ContextPath不是根目录("/")下无法正常运行的bug 67 | 1. 提供model中默认参数 __beat,便于在view中使用 68 | 1. 提供war:war打包plugin实例,移除web.xml的依赖 69 | 70 | ```xml 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-war-plugin 75 | 2.3 76 | 77 | false 78 | 79 | 80 | 81 | ``` 82 | 83 | [58同城]: http://www.58.com/ 84 | [约定优于配置]: http://zh.wikipedia.org/wiki/%E7%BA%A6%E5%AE%9A%E4%BC%98%E4%BA%8E%E9%85%8D%E7%BD%AE 85 | [guice]: http://code.google.com/p/google-guice/ 86 | [jetty:run]: http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin 87 | [tomcat7:run]: http://tomcat.apache.org/maven-plugin-2.0/tomcat7-maven-plugin/run-mojo.html 88 | 89 | -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | #*.jar 5 | *.war 6 | *.ear 7 | /target 8 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.bj58.spat 5 | argo 6 | 1.0.0 7 | 58.com argo 8 | 58.com argo 9 | https://github.com/58code/Argo 10 | 11 | 12 | 58.com 13 | http://www.58.com/ 14 | 15 | 16 | 17 | 18 | The Apache Software License, Version 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.txt 20 | repo 21 | 22 | 23 | 24 | 25 | 26 | SPAT 27 | Service Platform Architecture Team 28 | https://github.com/58code 29 | spat@58.com 30 | 31 | 32 | 33 | renjun 34 | renjun 35 | http://weibo.com/duoway 36 | rjun@outlook.com 37 | 38 | 39 | 40 | liuzw 41 | liu zhongwei 42 | liuzw@58.com 43 | 44 | 45 | 46 | 47 | scm:git:git://github.com/58code/Argo 48 | scm:git:git://github.com/58code/Argo 49 | https://github.com/58code/Argo 50 | 51 | 52 | 53 | 54 | 55 | com.google.guava 56 | guava 57 | 13.0.1 58 | 59 | 60 | 61 | com.google.inject 62 | guice 63 | 3.0 64 | 65 | 66 | 67 | org.javassist 68 | javassist 69 | 3.17.1-GA 70 | 71 | 72 | 73 | org.apache.velocity 74 | velocity 75 | 1.7 76 | 77 | 78 | 79 | org.slf4j 80 | slf4j-api 81 | 1.7.2 82 | 83 | 84 | 85 | org.slf4j 86 | slf4j-log4j12 87 | 1.7.2 88 | 89 | 90 | 91 | log4j 92 | log4j 93 | 1.2.16 94 | 95 | 96 | 97 | javax.servlet 98 | javax.servlet-api 99 | provided 100 | 3.0.1 101 | 102 | 103 | 104 | org.testng 105 | testng 106 | 6.8 107 | test 108 | 109 | 110 | 111 | org.mockito 112 | mockito-all 113 | 1.9.5 114 | test 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | maven-source-plugin 123 | 2.1 124 | 125 | true 126 | 127 | 128 | 129 | compile 130 | 131 | jar 132 | 133 | 134 | 135 | 136 | 137 | org.apache.maven.plugins 138 | maven-compiler-plugin 139 | 2.5.1 140 | 141 | 1.6 142 | 1.6 143 | UTF-8 144 | 145 | 146 | 147 | 148 | org.apache.maven.plugins 149 | maven-surefire-plugin 150 | 2.13 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/ActionResult.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo; 2 | 3 | /** 4 | * 所有Action的返回结果 5 | * 6 | */ 7 | public interface ActionResult { 8 | 9 | public final static ActionResult NULL = null; 10 | 11 | /** 12 | * 用于生成显示页面 13 | * 14 | * @param beatContext 需要渲染的上下文 15 | */ 16 | void render(BeatContext beatContext); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/ArgoController.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo; 2 | 3 | /** 4 | * 所有的Controller必须实现的接口 5 | * 6 | */ 7 | public interface ArgoController { 8 | 9 | /** 10 | * Controller被injector实例化后,将立即调用本方法进行初始化,代替构造函数 11 | */ 12 | void init(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/ArgoException.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo; 2 | 3 | import com.google.common.collect.Maps; 4 | 5 | import java.util.Map; 6 | 7 | public class ArgoException extends RuntimeException { 8 | 9 | public static ArgoExceptionBuilder newBuilder(String message) { 10 | return newBuilder(message, null); 11 | } 12 | 13 | public static ArgoExceptionBuilder newBuilder(Throwable cause) { 14 | return newBuilder("", cause); 15 | } 16 | 17 | public static ArgoExceptionBuilder newBuilder() { 18 | return newBuilder("", null); 19 | } 20 | 21 | public static ArgoExceptionBuilder newBuilder(String message, Throwable cause) { 22 | return new ArgoExceptionBuilder(message, cause); 23 | } 24 | 25 | private static final long serialVersionUID = 5099827279044223975L; 26 | 27 | 28 | ArgoException() { 29 | super(); 30 | } 31 | 32 | ArgoException(String message) { 33 | super(message); 34 | } 35 | 36 | ArgoException(Throwable cause) { 37 | super(cause); 38 | } 39 | 40 | ArgoException(String message, Throwable cause) { 41 | super(message, cause); 42 | } 43 | 44 | public static ArgoException raise(String message) { 45 | return new ArgoException(message); 46 | } 47 | 48 | public static ArgoException raise(Throwable cause) { 49 | return new ArgoException(cause); 50 | } 51 | 52 | public static ArgoException raise(String message, Throwable cause) { 53 | return new ArgoException(message, cause); 54 | } 55 | 56 | public static class ArgoExceptionBuilder { 57 | private final Map contextInfos = Maps.newLinkedHashMap(); 58 | 59 | private final Throwable cause; 60 | 61 | private final String currentMessage; 62 | 63 | ArgoExceptionBuilder(String message, Throwable cause) { 64 | this.currentMessage = message; 65 | this.cause = cause; 66 | } 67 | 68 | ArgoExceptionBuilder(Throwable cause) { 69 | this("", cause); 70 | } 71 | 72 | ArgoExceptionBuilder(String message) { 73 | this(message, null); 74 | } 75 | 76 | /** 77 | * 给异常增加上下文变量信息。 78 | * @param name 变量名 79 | * @param value 变量值 80 | * @return 自身 81 | */ 82 | public ArgoExceptionBuilder addContextVariable(String name, Object value) { 83 | contextInfos.put(name, value); 84 | return this; 85 | } 86 | 87 | public ArgoExceptionBuilder addContextVariables(Map variables) { 88 | for (Map.Entry entry : variables.entrySet()) 89 | addContextVariable(entry.toString(), entry.getValue()); 90 | 91 | return this; 92 | } 93 | 94 | /** 95 | * 创建一个ArgoException 96 | */ 97 | public ArgoException build() { 98 | return new ArgoException(getContextInfo(), cause); 99 | } 100 | 101 | /** 102 | * throw 103 | * @param clazz 104 | * @param 105 | * @return 106 | */ 107 | public T raise(Class clazz) { 108 | throw build(); 109 | } 110 | 111 | private String getContextInfo() { 112 | return this.currentMessage + 113 | (contextInfos.size() > 0 ? "\ncontext: " + contextInfos.toString() 114 | : ""); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/BeatContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo; 22 | 23 | import com.bj58.argo.client.ClientContext; 24 | import com.bj58.argo.lifecycle.Lifecycle; 25 | 26 | import javax.servlet.ServletContext; 27 | import javax.servlet.http.HttpServletRequest; 28 | import javax.servlet.http.HttpServletResponse; 29 | 30 | 31 | /** 32 | * 管理一个客户端请求的生命周期 33 | * 34 | */ 35 | public interface BeatContext { 36 | 37 | /** 38 | * MVC 中的Model, 以key,value形式存放,可以由Controller传个View 39 | * 40 | * @return 当前model 41 | */ 42 | Model getModel(); 43 | 44 | /** 45 | * 返回本次调用的 {@link HttpServletRequest}对象 46 | * 47 | * @return 当前请求 48 | */ 49 | HttpServletRequest getRequest(); 50 | 51 | /** 52 | * 返回本次调用的 {@link HttpServletResponse}对象 53 | * 54 | * @return 当前response 55 | */ 56 | HttpServletResponse getResponse(); 57 | 58 | /** 59 | * 得到ServletContext信息 60 | * 61 | * @return 当前ServletContext 62 | */ 63 | ServletContext getServletContext(); 64 | 65 | /** 66 | * 获得客户端的信息 67 | * 68 | * @return 客户端信息 69 | */ 70 | ClientContext getClient(); 71 | 72 | // /** 73 | // * 本次调用的生命周期 74 | // * @return 75 | // */ 76 | // Lifecycle getLifecycle(); 77 | 78 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/Model.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo; 2 | 3 | import com.bj58.argo.internal.DefaultModel; 4 | import com.google.inject.ImplementedBy; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Model,MVC中的M, 10 | * 用于将Controller中的数据传递给View 11 | * 12 | */ 13 | @ImplementedBy(DefaultModel.class) 14 | public interface Model { 15 | 16 | /** 17 | * 增加一个属性 18 | * @param attributeName 属性名称 19 | * @param attributeValue 属性值 20 | */ 21 | Model add(String attributeName, Object attributeValue); 22 | 23 | /** 24 | * 根据属性名得到属性值 25 | * @param attributeName 属性名称 26 | * @return 对应的属性值 27 | */ 28 | Object get(String attributeName); 29 | 30 | /** 31 | * Return the model map. Never returns null. 32 | * To be called by application code for modifying the model. 33 | */ 34 | Map getModel(); 35 | 36 | /** 37 | * 批量增加属性 38 | * @param attributes 属性map 39 | */ 40 | Model addAll(Map attributes); 41 | 42 | /** 43 | * 判断是否包含属性名 44 | * @param attributeName 需要查找的属性 45 | * @return 是否包含 46 | */ 47 | boolean contains(String attributeName); 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/annotations/GET.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.annotations; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * 标识Action所处理HTTP请求类型 8 | * 9 | * 处理除POST外所有HTTP method,包括 GET, HEAD等 10 | */ 11 | @Target({ElementType.METHOD, ElementType.TYPE}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Documented 14 | public @interface GET{ 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/annotations/POST.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.annotations; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 标识Action所处理HTTP POST请求类型 7 | * 8 | */ 9 | @Target({ElementType.METHOD, ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface POST { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/annotations/Path.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.annotations; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | 10 | /** 11 | * 标注资源类或方法的相对路径 12 | * 13 | */ 14 | @Target({ElementType.METHOD, ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Documented 17 | public @interface Path { 18 | 19 | /** 20 | * 对应的url相对路径 21 | * 可以使用正则表达式 22 | */ 23 | String value(); 24 | 25 | /** 26 | * 确定匹配的优先级 27 | * 28 | * @return 模式匹配的优先级 29 | */ 30 | int order() default 10000; 31 | 32 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/client/Cookies.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.client; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.google.inject.ImplementedBy; 5 | 6 | import javax.inject.Inject; 7 | import javax.servlet.http.Cookie; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | /** 12 | * 封装cookie管理 13 | */ 14 | @ImplementedBy(Cookies.DefaultCookies.class) 15 | public interface Cookies { 16 | 17 | /** 18 | * 通过名字和值新增一个cookie 19 | * @param name cookie名称,必须是ascii码和数字,其他会抛错 RFC2019 20 | * @param value cookie的值 21 | */ 22 | public void add(String name, String value); 23 | 24 | /** 25 | * 通过名字,值和有效期新增一个cookie 26 | * @param name cookie名称,必须是ascii码和数字,其他会抛错 RFC2019 27 | * @param value cookie的值 28 | * @param cookieMaxAge cookie的有效期 29 | */ 30 | public void add(String name, String value, int cookieMaxAge); 31 | 32 | /** 33 | * 新增一个cookie 34 | * @param cookie 35 | */ 36 | public void add(Cookie cookie); 37 | 38 | /** 39 | * 通过名字获得cookie的值,如果名字不存在,返回null 40 | * @param name 41 | * @return 42 | */ 43 | public String get(String name); 44 | 45 | /** 46 | * 根据名字获得对应Cookie,如果名字不存在,返回null 47 | * @param name 48 | * @return 49 | */ 50 | public Cookie getCookie(String name); 51 | 52 | /** 53 | * 获得所有的cookie数组,如果没有cookie数组,返回一个长度为0的数组,这样不用判断null。 54 | * @return 对应的cookie数组,不可能是null。 55 | */ 56 | public Cookie[] getCookies(); 57 | 58 | /** 59 | * 移除一个对应名称的cookie 60 | * @param name cookie名 61 | */ 62 | public void remove(String name); 63 | 64 | public static class DefaultCookies implements Cookies { 65 | 66 | private final HttpServletResponse response; 67 | private final HttpServletRequest request; 68 | 69 | private Cookie[] cookies = null; 70 | private static final Cookie[] emptyCookies = new Cookie[0]; 71 | 72 | @Inject 73 | public DefaultCookies(BeatContext beat) { 74 | response = beat.getResponse(); 75 | request = beat.getRequest(); 76 | 77 | } 78 | 79 | @Override 80 | public void add(String name, String value) { 81 | Cookie cookie = new Cookie(name, value); 82 | // 设置路径(默认) 83 | cookie.setPath("/"); 84 | // 把cookie放入响应中 85 | add(cookie); 86 | 87 | } 88 | 89 | @Override 90 | public void add(String name, String value, int cookieMaxAge) { 91 | Cookie cookie = new Cookie(name, value); 92 | // 设置有效日期 93 | cookie.setMaxAge(cookieMaxAge); 94 | // 设置路径(默认) 95 | cookie.setPath("/"); 96 | 97 | add(cookie); 98 | 99 | } 100 | 101 | @Override 102 | public void add(Cookie cookie) { 103 | response.addCookie(cookie); 104 | } 105 | 106 | @Override 107 | public String get(String name) { 108 | Cookie cookie = getCookie(name); 109 | return cookie == null? null : cookie.getValue(); 110 | } 111 | 112 | @Override 113 | public Cookie getCookie(String name) { 114 | Cookie[] cookies = getCookies(); 115 | 116 | for(Cookie cookie : cookies){ 117 | if(name.equalsIgnoreCase(cookie.getName())) 118 | return cookie; 119 | } 120 | 121 | return null; 122 | } 123 | 124 | @Override 125 | public Cookie[] getCookies() { 126 | 127 | if (cookies != null) 128 | return cookies; 129 | 130 | cookies = request.getCookies(); 131 | if (cookies == null) 132 | cookies = emptyCookies; 133 | 134 | return cookies; 135 | } 136 | 137 | @Override 138 | public void remove(String name) { 139 | Cookie cookie = getCookie(name); 140 | 141 | if (cookie == null) return; 142 | 143 | // 销毁 144 | cookie.setMaxAge(0); 145 | response.addCookie(cookie); 146 | } 147 | 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/client/SafeParameter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.client; 22 | 23 | import com.google.inject.ImplementedBy; 24 | 25 | import javax.inject.Singleton; 26 | 27 | /** 28 | * 从queryString或者form过来的参数进行安全清洗 29 | * 开发者可以自己重新注入 SafeParameter 的实现,来实现适合自己的安全参数 30 | * 31 | */ 32 | @ImplementedBy(SafeParameter.DefaultSafeParameter.class) 33 | public interface SafeParameter { 34 | 35 | /** 36 | * 将原始参数值安全编码后返回 37 | * 38 | * @param parameterValue 原始参数值 39 | * @return 安全参数值 40 | */ 41 | String encoding(String parameterValue); 42 | 43 | @Singleton 44 | public static class DefaultSafeParameter implements SafeParameter { 45 | 46 | @Override 47 | public String encoding(String parameterValue) { 48 | return parameterValue; 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/client/Upload.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.client; 2 | 3 | import javax.servlet.http.Part; 4 | 5 | /** 6 | * 上传文件的封装,继承与servlet3.0的 7 | * @see Part 8 | * 并增加了获得文件名的方法 9 | * 10 | */ 11 | public interface Upload extends Part { 12 | 13 | String getFileName(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/controller/ReverseProxy.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.controller; 2 | 3 | import com.google.common.net.InetAddresses; 4 | import com.google.inject.ImplementedBy; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import java.net.InetAddress; 8 | 9 | /** 10 | * 用于集群的反向代理(nginx/apache)后的web网站 11 | * 用于甄别用户真实的ip,防止ip欺诈 12 | * @author renjun 13 | */ 14 | @ImplementedBy(ReverseProxy.DefaultReverseProxy.class) 15 | public interface ReverseProxy { 16 | 17 | /** 18 | * a判断请求的ip是否是当前集群ip 19 | * @param address 需要判断的ip地址 20 | * @return true:是反向代理服务器地址; false:不是反向代理服务器地址,用户真实地址 21 | */ 22 | boolean isCluster(InetAddress address); 23 | 24 | 25 | /** 26 | * 从当前request头中获得用户的ip 27 | * 28 | * @param request 当前request 29 | * @return ip 30 | */ 31 | InetAddress getRemoteAddress(HttpServletRequest request); 32 | 33 | 34 | /** 35 | * 默认实现,依据用户的ip是否是10.*.*.*,192.168.*.*等判别是否是反向代理服务器 36 | * 如果是反向代理服务器,则应该重写request的头如x-forwarded-for 37 | * 38 | * refer to RFC 1918 39 | * 10/8 prefix 40 | * 172.16/12 prefix 41 | * 192.168/16 prefix 42 | */ 43 | public static class DefaultReverseProxy implements ReverseProxy { 44 | 45 | @Override 46 | public boolean isCluster(InetAddress address) { 47 | 48 | return !address.isSiteLocalAddress(); 49 | 50 | } 51 | 52 | @Override 53 | public InetAddress getRemoteAddress(HttpServletRequest request) { 54 | 55 | return InetAddresses.forString(getRemoteAddressByRequest(request)); 56 | } 57 | 58 | protected String getRemoteAddressByRequest(HttpServletRequest request) { 59 | return request.getHeader("x-forwarded-for"); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/controller/ViewFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.controller; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.internal.VelocityViewFactory; 5 | import com.google.inject.ImplementedBy; 6 | 7 | /** 8 | * 提供View工厂,默认采用velocity模板 9 | */ 10 | @ImplementedBy(VelocityViewFactory.class) 11 | public interface ViewFactory { 12 | ActionResult create(String viewName); 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/convention/EmptyModule.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.convention; 2 | 3 | import com.google.inject.Binder; 4 | import com.google.inject.Module; 5 | 6 | /** 7 | * 提供一个空的Module使用 8 | * 9 | */ 10 | public class EmptyModule implements Module { 11 | 12 | public static final EmptyModule instance = new EmptyModule(); 13 | 14 | @Override 15 | public void configure(Binder binder) { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/convention/GroupConvention.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.convention; 2 | 3 | 4 | import com.bj58.argo.ArgoController; 5 | import com.google.inject.Module; 6 | 7 | import java.io.File; 8 | import java.util.Set; 9 | 10 | /** 11 | * 这是一个组织级的约定规则 12 | *

13 | * convention over configuration 约定优于配置 14 | * http://zh.wikipedia.org/zh-cn/%E7%BA%A6%E5%AE%9A%E4%BC%98%E4%BA%8E%E9%85%8D%E7%BD%AE 15 | * 16 | * @author renjun 17 | */ 18 | public interface GroupConvention { 19 | 20 | /** 21 | * 用于自定义的组织的策略的类 22 | * 如果需要自己实现组织级的策略,需要实现这个各类 23 | * 可以在该类上配置注解 24 | * @see GroupConventionAnnotation 25 | * 也可以实现接口 26 | * @see GroupConvention 27 | * 28 | *
29 | * 30 | * 接口的优先级比annotation高 31 | * 32 | *
33 | * 34 | * 一个组织应该只提供一个实现类的jar包给其他项目约束。 35 | * 36 | */ 37 | public final static String annotatedGroupConventionBinder = "com.bj58.argo.GroupConventionBinder"; 38 | 39 | /** 40 | * 组织级配置 41 | * @return 组织级配置 42 | */ 43 | GroupConfig group(); 44 | 45 | /** 46 | * 项目级配置 47 | * @return 项目级配置 48 | */ 49 | ProjectConfig currentProject(); 50 | 51 | 52 | 53 | /** 54 | * 组织级配置文件,隶属于 55 | * @see com.bj58.argo.convention.GroupConvention#group() 56 | * 57 | * 为便于运维管理与维护及安全,需要将项目的配置文件日志单独区分开来,并统一管理 58 | */ 59 | public interface GroupConfig { 60 | 61 | /** 62 | * 公司级的配置文件路径,项目根据各自id对应相应文件夹放置配置文件 63 | * @return 公司级的配置文件路径 64 | */ 65 | File configFolder(); 66 | 67 | /** 68 | * 公司级的日志文件路径,项目根据各自id对应相应文件夹写日志文件 69 | * @return 公司级的日志文件路径 70 | */ 71 | File logFolder(); 72 | 73 | /** 74 | * 组织级的Guice注入module配置, 75 | * 在项目级的module后面实现,保证组织级的策略实现 76 | * 77 | * @return 组织级的Guice注入module配置 78 | */ 79 | Module module(); 80 | 81 | } 82 | 83 | /** 84 | * 项目级配置 85 | * @see com.bj58.argo.convention.GroupConvention#currentProject() 86 | */ 87 | public interface ProjectConfig { 88 | 89 | /** 90 | * 项目的Id,用于组织和运维进行统一管理 91 | */ 92 | String id(); 93 | 94 | /** 95 | * 项目所有的Controller集合 96 | * 97 | */ 98 | Set> controllerClasses(); 99 | 100 | /** 101 | * 项目级的注入配置 102 | * 103 | */ 104 | Module module(); 105 | } 106 | 107 | 108 | } 109 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/convention/GroupConventionAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.convention; 2 | 3 | import com.google.inject.Module; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | 12 | /** 13 | * 这是一个组织级的约定规则 14 | *

15 | * convention over configuration 约定优于配置 16 | * http://zh.wikipedia.org/zh-cn/%E7%BA%A6%E5%AE%9A%E4%BC%98%E4%BA%8E%E9%85%8D%E7%BD%AE 17 | * 18 | * @author renjun 19 | */ 20 | @Target({ElementType.TYPE}) 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Documented 23 | public @interface GroupConventionAnnotation { 24 | 25 | 26 | /** 27 | * 约定组织中所有项目必须实现的类, 28 | * @see com.bj58.argo.convention.GroupConvention.ProjectConfig 29 | * 30 | * 该类实现项目的Id用于项目的唯一编号,并便于管理 31 | * @see com.bj58.argo.convention.GroupConvention.ProjectConfig#id() 32 | * 33 | * 同时实现module, 34 | * @see com.bj58.argo.convention.GroupConvention.ProjectConfig#module() 35 | * 用于项目的Guice注入配置,优先级低于组织的module并可能会被组织级的module覆盖 36 | * 37 | */ 38 | String projectConventionClass() default "com.bj58.argo.ProjectConfigBinder"; 39 | 40 | /** 41 | * group级的注入Module 42 | * 可以覆盖项目级的module,保证组织的策略实施 43 | * 44 | */ 45 | Class groupModule() default EmptyModule.class; 46 | 47 | /** 48 | * 配置文件夹位置 49 | * 50 | * @return 配置文件夹的根目录 51 | */ 52 | String groupConfigFolder() default "/opt/argo"; 53 | 54 | String groupLogFolder() default "{groupConfigFolder}/log"; 55 | 56 | 57 | /** 58 | * group包的前缀,Argo将只扫描该前缀下的类 59 | * @return group包的前缀 60 | */ 61 | String groupPackagesPrefix() default "com.bj58.argo"; 62 | 63 | /** 64 | * controller的类名强制检查约定 65 | * 只有符合匹配条件的controller才能被Argo管理,保证组织级代码风格一致 66 | * 67 | */ 68 | String controllerPattern() default ".*\\.controllers\\..*Controller"; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/convention/GroupConventionFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.convention; 2 | 3 | import com.bj58.argo.internal.DefaultGroupConvention; 4 | import com.google.common.base.Throwables; 5 | 6 | import java.io.File; 7 | import java.net.URISyntaxException; 8 | import java.net.URL; 9 | 10 | /** 11 | * 获得GroupConvention的工厂 12 | */ 13 | public class GroupConventionFactory { 14 | 15 | 16 | public static GroupConvention getGroupConvention() { 17 | 18 | String className = GroupConvention.annotatedGroupConventionBinder; 19 | 20 | Class clazz = null; 21 | GroupConvention groupConvention; 22 | try { 23 | clazz = GroupConventionFactory.class.getClassLoader().loadClass(className); 24 | groupConvention = GroupConvention.class.cast(clazz); 25 | } catch (Exception e) { 26 | groupConvention = null; 27 | } 28 | 29 | if (groupConvention != null) 30 | return groupConvention; 31 | 32 | if (clazz == null || clazz.getAnnotation(GroupConventionAnnotation.class) == null) 33 | clazz = DefaultGroupConvention.class; 34 | 35 | GroupConventionAnnotation conventionAnnotation = clazz.getAnnotation(GroupConventionAnnotation.class); 36 | 37 | 38 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 39 | 40 | URL url = cl.getResource("."); 41 | 42 | File folder = null; 43 | try { 44 | folder = new File(url.toURI()); 45 | } catch (URISyntaxException e) { 46 | Throwables.propagate(e); 47 | } 48 | 49 | return new DefaultGroupConvention(conventionAnnotation, folder); 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/convention/GroupConventionUtils.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.convention; 2 | 3 | import com.bj58.argo.ArgoException; 4 | import com.google.common.base.Strings; 5 | 6 | import java.io.File; 7 | 8 | /** 9 | * GroupConvetion工具 10 | */ 11 | public class GroupConventionUtils { 12 | 13 | private GroupConventionUtils() {} 14 | 15 | public static File configFolder(GroupConvention groupConvention) { 16 | File file = groupConvention.group().configFolder(); 17 | String projectId = groupConvention.currentProject().id(); 18 | 19 | file = Strings.isNullOrEmpty(projectId) 20 | ? file 21 | : new File(file, projectId); 22 | 23 | return buildDirectory(file); 24 | } 25 | 26 | public static File logFolder(GroupConvention groupConvention) { 27 | File file = groupConvention.group().logFolder(); 28 | String projectId = groupConvention.currentProject().id(); 29 | 30 | file = Strings.isNullOrEmpty(projectId) 31 | ? file 32 | : new File(file, projectId); 33 | 34 | return buildDirectory(file); 35 | } 36 | 37 | private static File buildDirectory(File file) { 38 | if (file.isDirectory()) 39 | return file; 40 | 41 | if (file.exists()) 42 | throw ArgoException.raise(String.format("File %s has exist, but not directory.", file)); 43 | 44 | if (!file.mkdirs()) 45 | throw ArgoException.raise(String.format("Failed to getLogger directory %s.", file)); 46 | 47 | return file; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/convention/ProjectConvention.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.convention; 2 | 3 | import com.google.inject.Module; 4 | 5 | import java.io.File; 6 | import java.util.Collection; 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | /** 11 | * 每个项目需要实现的项目级约定 12 | * @see com.bj58.argo.convention.GroupConventionAnnotation#projectConventionClass() 13 | */ 14 | public interface ProjectConvention extends Module{ 15 | 16 | /** 17 | * 提供项目的编号 18 | */ 19 | String id(); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/inject/ArgoModule.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.inject; 2 | 3 | import com.bj58.argo.*; 4 | import com.bj58.argo.client.ClientContext; 5 | import com.bj58.argo.client.ClientContext.DefaultClientContext; 6 | import com.bj58.argo.convention.GroupConvention; 7 | import com.bj58.argo.internal.DefaultBeatContext; 8 | import com.bj58.argo.internal.DefaultModel; 9 | import com.bj58.argo.internal.DefaultMultipartConfigElementProvider; 10 | import com.bj58.argo.internal.StaticFilesAction; 11 | import com.bj58.argo.internal.actionresult.StatusCodeActionResult; 12 | import com.bj58.argo.route.Action; 13 | import com.bj58.argo.route.StaticActionAnnotation; 14 | import com.google.inject.AbstractModule; 15 | import com.google.inject.Provides; 16 | import com.google.inject.name.Names; 17 | 18 | import javax.inject.Singleton; 19 | import javax.servlet.MultipartConfigElement; 20 | import javax.servlet.ServletContext; 21 | import javax.servlet.ServletRequest; 22 | import javax.servlet.ServletResponse; 23 | import javax.servlet.http.HttpServletRequest; 24 | import javax.servlet.http.HttpServletResponse; 25 | import java.util.Set; 26 | import java.util.concurrent.Executor; 27 | import java.util.concurrent.Executors; 28 | 29 | 30 | /** 31 | * argo的默认注入,所有注入项都可以被project级及group级注入覆盖 32 | * 优先级有低到高的顺序是 33 | * Argo 34 | * @see com.bj58.argo.convention.ProjectConvention 35 | * @see com.bj58.argo.convention.GroupConvention.ProjectConfig#module() 36 | * 37 | * @author renjun 38 | */ 39 | public class ArgoModule extends AbstractModule { 40 | 41 | private final Argo argo; 42 | 43 | public ArgoModule(Argo argo) { 44 | 45 | this.argo = argo; 46 | 47 | } 48 | 49 | @Override 50 | protected void configure() { 51 | 52 | bind(ServletRequest.class).to(HttpServletRequest.class); 53 | bind(ServletResponse.class).to(HttpServletResponse.class); 54 | 55 | bind(BeatContext.class) 56 | .annotatedWith(ArgoSystem.class) 57 | .to(DefaultBeatContext.class); 58 | 59 | bind(ActionResult.class) 60 | .annotatedWith(Names.named("HTTP_STATUS=404")) 61 | .toInstance(StatusCodeActionResult.defaultSc404); 62 | 63 | bind(ActionResult.class) 64 | .annotatedWith(Names.named("HTTP_STATUS=405")) 65 | .toInstance(StatusCodeActionResult.defaultSc405); 66 | 67 | bind(Action.class).annotatedWith(StaticActionAnnotation.class) 68 | .to(StaticFilesAction.class); 69 | 70 | bind(ClientContext.class).to(DefaultClientContext.class); 71 | bind(Model.class).to(DefaultModel.class); 72 | 73 | bind(MultipartConfigElement.class) 74 | .toProvider(DefaultMultipartConfigElementProvider.class) 75 | .in(Singleton.class); 76 | 77 | // bind all controllers. 78 | for (Class clazz : argo.getControllerClasses()) 79 | bind(clazz).in(Singleton.class); 80 | } 81 | 82 | 83 | @Provides 84 | private HttpServletRequest provideReuqest() { 85 | return argo.currentRequest(); 86 | } 87 | 88 | @Provides 89 | private HttpServletResponse provideResponse() { 90 | return argo.currentResponse(); 91 | } 92 | 93 | @Provides 94 | @ArgoSystem 95 | @Singleton 96 | private Set> provideControllerClasses() { 97 | return argo.getControllerClasses(); 98 | } 99 | 100 | 101 | @Provides 102 | @Singleton 103 | private GroupConvention provideGroupConvention() { 104 | return argo.groupConvention(); 105 | } 106 | 107 | @Provides 108 | @Singleton 109 | private Argo provideArgo() { 110 | return argo; 111 | } 112 | 113 | @Provides 114 | @Singleton 115 | private ServletContext provideServletContext() { 116 | return argo.servletContext(); 117 | } 118 | 119 | @Provides 120 | @Singleton 121 | private BeatContext provideBeatContext() { 122 | return argo.beatContext(); 123 | } 124 | 125 | @Provides 126 | @ArgoSystem 127 | @Singleton 128 | private Executor provideExecutor() { 129 | return Executors.newCachedThreadPool(); 130 | } 131 | 132 | 133 | @Provides 134 | @Singleton 135 | private GroupConvention.GroupConfig provideGroupConfig() { 136 | return argo.groupConvention().group(); 137 | } 138 | 139 | @Provides 140 | @Singleton 141 | private GroupConvention.ProjectConfig provideProjectConfig() { 142 | return argo.groupConvention().currentProject(); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/inject/ArgoSystem.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.inject; 2 | 3 | import com.google.inject.BindingAnnotation; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 用于Argo内部注入用 12 | * 13 | */ 14 | @BindingAnnotation 15 | @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE}) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface ArgoSystem { 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/interceptor/ExceptInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.interceptor; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.BeatContext; 5 | 6 | /** 7 | * 出错拦截器 8 | * TODO: 还未实现 9 | */ 10 | public interface ExceptInterceptor { 11 | 12 | Throwable[] getExceptionScopes(); 13 | 14 | ActionResult catchMe(Throwable e, BeatContext beatContext); 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/interceptor/PostInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.interceptor; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.BeatContext; 5 | 6 | /** 7 | * 方法执行完成后的拦截处理,可以与 8 | * @see PreInterceptor 9 | * 共同实现,也可以单独使用 10 | * 11 | * @see PostInterceptorAnnotation 12 | */ 13 | public interface PostInterceptor { 14 | 15 | /** 16 | * 拦截当前请求 17 | * @param beat 当前请求的上下文 18 | * @return 19 | * null,进入下一个拦截或执行Action 20 | *
21 | * 非空,直接显示,不进入下一个拦截或执行Action 22 | */ 23 | public ActionResult postExecute(BeatContext beat, ActionResult executionResult); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/interceptor/PostInterceptorAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.interceptor; 2 | 3 | import com.bj58.argo.interceptor.PostInterceptor; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * 设置拦截器 9 | * @author renjun 10 | * 11 | */ 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Documented 15 | public @interface PostInterceptorAnnotation { 16 | Class value(); 17 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/interceptor/PreInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.interceptor; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.BeatContext; 5 | 6 | /** 7 | * 方法执行前的拦截处理,可以与 8 | * @see PostInterceptor 9 | * 共同实现,也可以单独使用 10 | * 11 | * @see PreInterceptorAnnotation 12 | */ 13 | public interface PreInterceptor { 14 | 15 | /** 16 | * 拦截当前请求 17 | * @param beat 当前请求的上下文 18 | * @return 19 | * null,进入下一个拦截或执行Action 20 | *
21 | * 非空,直接显示,不进入下一个拦截或执行Action 22 | */ 23 | public ActionResult preExecute(BeatContext beat); 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/interceptor/PreInterceptorAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.interceptor; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 设置拦截器 7 | * @author renjun 8 | * 9 | */ 10 | @Target(ElementType.TYPE) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | public @interface PreInterceptorAnnotation { 14 | Class value(); 15 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/BeatContextWrapper.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.bj58.argo.Model; 5 | import com.bj58.argo.client.ClientContext; 6 | 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | public class BeatContextWrapper implements BeatContext { 12 | 13 | private BeatContext beatContext; 14 | 15 | public BeatContextWrapper(BeatContext beatContext) { 16 | this.beatContext = beatContext; 17 | } 18 | 19 | @Override 20 | public Model getModel() { 21 | return beatContext.getModel(); 22 | } 23 | 24 | @Override 25 | public HttpServletRequest getRequest() { 26 | return beatContext.getRequest(); 27 | } 28 | 29 | @Override 30 | public HttpServletResponse getResponse() { 31 | return beatContext.getResponse(); 32 | } 33 | 34 | @Override 35 | public ServletContext getServletContext() { 36 | return beatContext.getServletContext(); 37 | } 38 | 39 | @Override 40 | public ClientContext getClient() { 41 | return beatContext.getClient(); 42 | } 43 | 44 | // @Override 45 | // public Lifecycle getLifecycle() { 46 | // return beatContext.getLifecycle(); 47 | // } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/ControllerInfo.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.Argo; 5 | import com.bj58.argo.ArgoController; 6 | import com.bj58.argo.annotations.GET; 7 | import com.bj58.argo.annotations.POST; 8 | import com.bj58.argo.annotations.Path; 9 | import com.bj58.argo.thirdparty.AnnotationUtils; 10 | import com.google.common.base.Predicate; 11 | import com.google.common.collect.ImmutableSet; 12 | import com.google.common.collect.Lists; 13 | import com.google.common.collect.Sets; 14 | 15 | import java.lang.annotation.Annotation; 16 | import java.lang.reflect.Method; 17 | import java.lang.reflect.Modifier; 18 | import java.util.List; 19 | import java.util.Set; 20 | 21 | public class ControllerInfo { 22 | 23 | 24 | final ArgoController controller; 25 | final Class clazz; 26 | final Path path; 27 | final boolean isGet; 28 | final boolean isPost; 29 | final String pathUrl; 30 | 31 | final Set annotations; 32 | 33 | 34 | public ControllerInfo(ArgoController controller) { 35 | this.controller = controller; 36 | clazz = controller.getClass(); 37 | this.path = AnnotationUtils.findAnnotation(clazz, Path.class); 38 | 39 | boolean isGet = AnnotationUtils.findAnnotation(clazz, GET.class) != null; 40 | boolean isPost = AnnotationUtils.findAnnotation(clazz, POST.class) != null; 41 | 42 | if (!isGet && !isPost) { 43 | isGet = true; 44 | isPost = true; 45 | } 46 | 47 | this.isGet = isGet; 48 | this.isPost = isPost; 49 | 50 | this.annotations = ImmutableSet.copyOf(clazz.getAnnotations()); 51 | 52 | String pathUrl = path == null ? "/" : path.value(); 53 | 54 | if (pathUrl.length() == 0 || pathUrl.charAt(0) != '/') 55 | pathUrl = '/' + pathUrl; 56 | 57 | this.pathUrl = pathUrl; 58 | 59 | } 60 | 61 | public List analyze() { 62 | List actions = Lists.newArrayList(); 63 | 64 | 65 | Set sets = Sets.filter( 66 | Sets.newHashSet(clazz.getDeclaredMethods()) 67 | , methodFilter); 68 | //TODO : checkMe 69 | for(Method method : sets){ 70 | 71 | //todo: argo.instance 72 | actions.add(new ActionInfo(this, method, Argo.instance)); 73 | } 74 | 75 | 76 | return actions; 77 | } 78 | 79 | 80 | public ArgoController getController() { 81 | return controller; 82 | } 83 | 84 | public Class getClazz() { 85 | return clazz; 86 | } 87 | 88 | public Path getPath() { 89 | return path; 90 | } 91 | 92 | public boolean isGet() { 93 | return isGet; 94 | } 95 | 96 | public boolean isPost() { 97 | return isPost; 98 | } 99 | 100 | public String getPathUrl() { 101 | return pathUrl; 102 | } 103 | 104 | public Set getAnnotations() { 105 | return annotations; 106 | } 107 | 108 | public static Predicate getMethodFilter() { 109 | return methodFilter; 110 | } 111 | 112 | private final static Predicate methodFilter = new Predicate() { 113 | @Override 114 | public boolean apply(Method method) { 115 | // if (AnnotationUtils.findAnnotation(method, Ignored.class) != null) return false; 116 | 117 | //TODO : 新增类别校验,如果不包含Path则不加载到ActionInfo 中 118 | if (AnnotationUtils.findAnnotation(method, Path.class) == null) return false; 119 | Class returnType = method.getReturnType(); 120 | return returnType != null 121 | && ActionResult.class.isAssignableFrom(returnType) 122 | && (!method.isBridge() //TODO: 是否需要处理 123 | && method.getDeclaringClass() != Object.class 124 | && Modifier.isPublic(method.getModifiers())); 125 | } 126 | }; 127 | 128 | } 129 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultArgoDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.Argo; 5 | import com.bj58.argo.BeatContext; 6 | import com.bj58.argo.inject.ArgoSystem; 7 | import com.bj58.argo.internal.actionresult.StatusCodeActionResult; 8 | import com.bj58.argo.logs.Logger; 9 | import com.bj58.argo.route.Router; 10 | import com.bj58.argo.servlet.ArgoDispatcher; 11 | import com.bj58.argo.servlet.ArgoRequest; 12 | import com.bj58.argo.utils.OnlyOnceCondition; 13 | import com.google.common.io.Closeables; 14 | import com.google.inject.Key; 15 | import com.google.inject.OutOfScopeException; 16 | 17 | import javax.inject.Inject; 18 | import javax.inject.Singleton; 19 | import javax.servlet.MultipartConfigElement; 20 | import javax.servlet.http.HttpServletRequest; 21 | import javax.servlet.http.HttpServletResponse; 22 | 23 | /** 24 | * 25 | * 用于处理Rest请求调度的核心类 26 | * 27 | */ 28 | @Singleton 29 | public class DefaultArgoDispatcher implements ArgoDispatcher { 30 | 31 | private final Argo argo; 32 | 33 | private final Router router; 34 | 35 | private final StatusCodeActionResult statusCodeActionResult; 36 | 37 | private final Key defaultBeatContextKey = Key.get(BeatContext.class, ArgoSystem.class); 38 | 39 | private final MultipartConfigElement config; 40 | 41 | private final Logger logger; 42 | 43 | 44 | @Inject 45 | public DefaultArgoDispatcher(Argo argo, Router router, StatusCodeActionResult statusCodeActionResult, MultipartConfigElement config) { 46 | 47 | this.argo = argo; 48 | 49 | this.router = router; 50 | this.statusCodeActionResult = statusCodeActionResult; 51 | this.config = config; 52 | 53 | this.logger = argo.getLogger(this.getClass()); 54 | 55 | logger.info("constructed.", this.getClass()); 56 | } 57 | 58 | @Override 59 | public void init() { 60 | } 61 | 62 | @Override 63 | public void service(HttpServletRequest request, HttpServletResponse response) { 64 | 65 | ArgoRequest argoRequest = new ArgoRequest(request, config); 66 | 67 | try { 68 | BeatContext beatContext = bindBeatContext(argoRequest, response); 69 | 70 | route(beatContext); 71 | } finally { 72 | Closeables.closeQuietly(argoRequest); 73 | } 74 | } 75 | 76 | private BeatContext bindBeatContext(HttpServletRequest request, HttpServletResponse response) { 77 | Context context = new Context(request, response); 78 | localContext.set(context); 79 | 80 | BeatContext beat = argo.injector().getInstance(defaultBeatContextKey); 81 | // 增加默认参数到model 82 | beat.getModel().add("__beat", beat); 83 | context.setBeat(beat); 84 | return beat; 85 | } 86 | 87 | private void route(BeatContext beat) { 88 | try { 89 | ActionResult result = router.route(beat); 90 | 91 | if (ActionResult.NULL == result) 92 | result = statusCodeActionResult.getSc404(); 93 | 94 | result.render(beat); 95 | 96 | } catch (Exception e) { 97 | 98 | statusCodeActionResult.render405(beat); 99 | 100 | e.printStackTrace(); 101 | 102 | logger.error(String.format("fail to route. url:%s", beat.getClient().getRelativeUrl()), e); 103 | 104 | //TODO: catch any exceptions. 105 | 106 | } finally { 107 | localContext.remove(); 108 | } 109 | } 110 | 111 | public void destroy() { 112 | } 113 | 114 | public HttpServletRequest currentRequest() { 115 | return getContext().getRequest(); 116 | } 117 | 118 | public HttpServletResponse currentResponse() { 119 | return getContext().getResponse(); 120 | } 121 | 122 | public BeatContext currentBeatContext() { 123 | return getContext().getBeat(); 124 | } 125 | 126 | 127 | private Context getContext() { 128 | Context context = localContext.get(); 129 | if (context == null) { 130 | throw new OutOfScopeException("Cannot access scoped object. Either we" 131 | + " are not currently inside an HTTP Servlet currentRequest, or you may" 132 | + " have forgotten to apply " + DefaultArgoDispatcher.class.getName() 133 | + " as a servlet filter for this currentRequest."); 134 | } 135 | return context; 136 | } 137 | 138 | final ThreadLocal localContext = new ThreadLocal(); 139 | 140 | private static class Context { 141 | 142 | final HttpServletRequest request; 143 | final HttpServletResponse response; 144 | 145 | BeatContext beat; 146 | 147 | OnlyOnceCondition onlyOnce = OnlyOnceCondition.create("The current beat has been created."); 148 | 149 | Context(HttpServletRequest request, HttpServletResponse response) { 150 | this.request = request; 151 | this.response = response; 152 | } 153 | 154 | HttpServletRequest getRequest() { 155 | return request; 156 | } 157 | 158 | HttpServletResponse getResponse() { 159 | return response; 160 | } 161 | 162 | BeatContext getBeat() { 163 | return beat; 164 | } 165 | 166 | void setBeat(BeatContext beat) { 167 | onlyOnce.check(); 168 | this.beat = beat; 169 | } 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultBeatContext.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.bj58.argo.client.ClientContext; 5 | import com.bj58.argo.inject.ArgoSystem; 6 | import com.bj58.argo.Model; 7 | 8 | import javax.inject.Inject; 9 | import javax.servlet.ServletContext; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | @ArgoSystem 14 | public class DefaultBeatContext implements BeatContext { 15 | 16 | private final HttpServletRequest request; 17 | private final HttpServletResponse response; 18 | private final Model model; 19 | private final ClientContext clientContext; 20 | private final ServletContext servletContext; 21 | 22 | @Inject 23 | public DefaultBeatContext(HttpServletRequest request, HttpServletResponse response, Model model, ClientContext clientContext, ServletContext servletContext) { 24 | this.request = request; 25 | this.response = response; 26 | this.model = model; 27 | this.clientContext = clientContext; 28 | this.servletContext = servletContext; 29 | } 30 | 31 | @Override 32 | public Model getModel() { 33 | return model; 34 | } 35 | 36 | @Override 37 | public HttpServletRequest getRequest() { 38 | return request; 39 | } 40 | 41 | @Override 42 | public HttpServletResponse getResponse() { 43 | return response; 44 | } 45 | 46 | @Override 47 | public ServletContext getServletContext() { 48 | return servletContext; 49 | } 50 | 51 | @Override 52 | public ClientContext getClient() { 53 | return clientContext; 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultLogger.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | 4 | import com.bj58.argo.logs.Logger; 5 | 6 | import javax.inject.Inject; 7 | 8 | public class DefaultLogger implements Logger { 9 | 10 | private final org.slf4j.Logger logger; 11 | 12 | @Inject 13 | public DefaultLogger(org.slf4j.Logger logger) { 14 | this.logger = logger; 15 | } 16 | 17 | 18 | @Override 19 | public void debug(String msg) { 20 | logger.debug(msg); 21 | } 22 | 23 | @Override 24 | public void debug(String format, Object arg) { 25 | logger.debug(format, arg); 26 | } 27 | 28 | @Override 29 | public void debug(String msg, Throwable t) { 30 | logger.debug(msg, t); 31 | } 32 | 33 | @Override 34 | public void info(String msg) { 35 | logger.info(msg); 36 | } 37 | 38 | @Override 39 | public void info(String format, Object arg) { 40 | logger.info(format, arg); 41 | } 42 | 43 | @Override 44 | public void info(String msg, Throwable t) { 45 | logger.info(msg, t); 46 | } 47 | 48 | @Override 49 | public void error(String msg) { 50 | logger.error(msg); 51 | } 52 | 53 | @Override 54 | public void error(String msg, Throwable t) { 55 | logger.error(msg, t); 56 | } 57 | 58 | @Override 59 | public void error(String format, Object arg) { 60 | logger.error(format, arg); 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return logger.toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultLoggerFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.Argo; 4 | import com.bj58.argo.ArgoException; 5 | import com.bj58.argo.convention.GroupConventionUtils; 6 | import com.bj58.argo.logs.LogConfigure; 7 | import com.bj58.argo.logs.Logger; 8 | import com.bj58.argo.logs.LoggerFactory; 9 | import com.google.common.base.Strings; 10 | import com.google.common.collect.ImmutableMap; 11 | import com.google.common.collect.Maps; 12 | import com.google.common.io.Closeables; 13 | import org.apache.log4j.BasicConfigurator; 14 | import org.apache.log4j.PropertyConfigurator; 15 | 16 | import javax.inject.Inject; 17 | import javax.inject.Singleton; 18 | import java.io.File; 19 | import java.io.FileReader; 20 | import java.io.Reader; 21 | import java.util.Map; 22 | import java.util.Properties; 23 | 24 | @Singleton 25 | public class DefaultLoggerFactory implements LoggerFactory { 26 | 27 | private static final String configFileName = "log4j.properties"; 28 | 29 | Map loggerMap = Maps.newHashMap(); 30 | 31 | @Inject 32 | public DefaultLoggerFactory(LogConfigure logConfigure) { 33 | logConfigure.configure(); 34 | } 35 | 36 | @Override 37 | public Logger getLogger(String name) { 38 | 39 | Logger logger = null; 40 | 41 | synchronized (this) { 42 | logger = loggerMap.get(name); 43 | if (logger != null) 44 | return logger; 45 | 46 | org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger(name); 47 | 48 | logger = new DefaultLogger(slf4jLogger); 49 | 50 | loggerMap.put(name, logger); 51 | } 52 | 53 | return logger; 54 | } 55 | 56 | @Override 57 | public Logger getLogger(Class clazz) { 58 | 59 | return getLogger(clazz.getName()); 60 | 61 | } 62 | 63 | @Singleton 64 | public static class DefaultLog4jConfigure implements LogConfigure { 65 | 66 | private Argo argo; 67 | 68 | @Inject 69 | public DefaultLog4jConfigure(Argo argo) { 70 | this.argo = argo; 71 | } 72 | 73 | @Override 74 | public void configure() { 75 | 76 | Properties properties = configureFile(); 77 | 78 | if (properties == null) 79 | properties = defaultProperties(); 80 | 81 | configure(properties); 82 | 83 | } 84 | 85 | protected Properties configureFile() { 86 | File configFolder = GroupConventionUtils.configFolder(argo.groupConvention()); 87 | 88 | File configFile = new File(configFolder, configFileName); 89 | 90 | if (!configFile.exists()) 91 | return null; 92 | 93 | Properties properties = new Properties(); 94 | Reader reader = null; 95 | try { 96 | reader = new FileReader(configFile); 97 | properties.load(reader); 98 | } catch (Exception e) { 99 | throw ArgoException.raise("fail to init log config file.", e); 100 | } finally{ 101 | Closeables.closeQuietly(reader); 102 | } 103 | 104 | if (!properties.containsKey("log4j.appender.file.File")) 105 | properties.put("log4j.appender.file.File", defaultLogFile()); 106 | 107 | return properties; 108 | 109 | } 110 | 111 | protected Properties defaultProperties() { 112 | 113 | Properties properties = new Properties(); 114 | 115 | properties.put("log4j.rootLogger", "INFO, file"); 116 | properties.put("log4j.appender.file.File", defaultLogFile()); 117 | 118 | properties.put("log4j.appender.file.DatePattern","'.'yyyy-MM-dd"); 119 | properties.put("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender"); 120 | properties.put("log4j.appender.stdout.Target", "System.out"); 121 | properties.put("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout"); 122 | properties.put("log4j.appender.stdout.layout.ConversionPattern", "%m%n"); 123 | properties.put("log4j.appender.file", "org.apache.log4j.DailyRollingFileAppender"); 124 | properties.put("log4j.appender.file.Append", "true"); 125 | properties.put("log4j.appender.file.Threshold", "INFO"); 126 | properties.put("log4j.appender.file.layout", "org.apache.log4j.PatternLayout"); 127 | properties.put("log4j.appender.file.layout.ConversionPattern", "%d{ABSOLUTE} %5p %c{1}:%L - %m%n"); 128 | 129 | return properties; 130 | } 131 | 132 | private String defaultLogFile() { 133 | 134 | File logFolder = GroupConventionUtils.logFolder(argo.groupConvention()); 135 | 136 | String projectId = argo.groupConvention().currentProject().id(); 137 | 138 | if (Strings.isNullOrEmpty(projectId)) 139 | projectId = "argo"; 140 | 141 | File logFile = new File(logFolder 142 | , projectId + ".log"); 143 | 144 | return logFile.getAbsolutePath(); 145 | } 146 | 147 | private void configure(Properties properties) { 148 | PropertyConfigurator.configure(properties); 149 | } 150 | 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultModel.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.Model; 4 | import com.google.common.collect.Maps; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * MVC 中的Model, 以key,value形式存放,可以由Controller传个View 10 | * @author renjun 11 | * 12 | */ 13 | public class DefaultModel implements Model { 14 | 15 | /** Model Map */ 16 | private Map data = Maps.newConcurrentMap(); 17 | 18 | /** 19 | * 增加一个属性 20 | * @param attributeName 属性名称 21 | * @param attributeValue 属性值 22 | */ 23 | @Override 24 | public Model add(String attributeName, Object attributeValue) { 25 | data.put(attributeName, attributeValue); 26 | return this; 27 | } 28 | 29 | 30 | 31 | /** 32 | * 根据属性名得到属性值 33 | * @param attributeName 属性名称 34 | * @return 对应的属性值 35 | */ 36 | @Override 37 | public Object get(String attributeName) { 38 | return data.get(attributeName); 39 | } 40 | 41 | 42 | 43 | 44 | /** 45 | * Return the model map. Never returns null. 46 | * To be called by application code for modifying the model. 47 | */ 48 | @Override 49 | public Map getModel() { 50 | return data; 51 | } 52 | 53 | /** 54 | * 批量增加属性 55 | * @param attributes 56 | */ 57 | @Override 58 | public Model addAll(Map attributes) { 59 | data.putAll(attributes); 60 | return this; 61 | } 62 | 63 | /** 64 | * 判断是否包含属性名 65 | * @param attributeName 需要查找的属性 66 | * @return 67 | */ 68 | @Override 69 | public boolean contains(String attributeName) { 70 | return data.containsKey(attributeName); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultMultipartConfigElementProvider.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.ArgoException; 4 | import com.google.inject.Provider; 5 | 6 | import javax.inject.Inject; 7 | import javax.inject.Singleton; 8 | import javax.servlet.MultipartConfigElement; 9 | import javax.servlet.Servlet; 10 | import javax.servlet.ServletContext; 11 | import java.io.File; 12 | import java.io.IOException; 13 | 14 | @Singleton 15 | public class DefaultMultipartConfigElementProvider implements Provider { 16 | 17 | private final MultipartConfigElement config; 18 | @Inject 19 | public DefaultMultipartConfigElementProvider(ServletContext servletContext) { 20 | try { 21 | File tempDir = (File)servletContext.getAttribute("javax.servlet.context.tempdir"); 22 | config = new MultipartConfigElement(tempDir.getCanonicalPath()); 23 | } catch (IOException e) { 24 | throw ArgoException.raise(e); 25 | } 26 | 27 | } 28 | 29 | @Override 30 | public MultipartConfigElement get() { 31 | return config; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/DefaultRouter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.Argo; 4 | import com.bj58.argo.ArgoController; 5 | import com.bj58.argo.BeatContext; 6 | import com.bj58.argo.inject.ArgoSystem; 7 | import com.bj58.argo.ActionResult; 8 | import com.bj58.argo.logs.Logger; 9 | import com.bj58.argo.route.*; 10 | import com.google.common.base.Function; 11 | import com.google.common.collect.ImmutableList; 12 | import com.google.common.collect.ImmutableSet; 13 | import com.google.common.collect.Iterables; 14 | import com.google.common.collect.Lists; 15 | 16 | import javax.inject.Inject; 17 | import javax.inject.Singleton; 18 | import java.util.List; 19 | import java.util.Set; 20 | 21 | @Singleton 22 | public class DefaultRouter implements Router { 23 | 24 | private final Argo argo; 25 | private final List actions; 26 | 27 | @Inject 28 | public DefaultRouter(Argo argo, @ArgoSystem Set> controllerClasses, @StaticActionAnnotation Action staticAction) { 29 | 30 | this.argo = argo; 31 | 32 | argo.getLogger().info("initializing a %s(implements Router)", this.getClass()); 33 | 34 | this.actions = buildActions(argo, controllerClasses, staticAction); 35 | 36 | argo.getLogger().info("%s(implements Router) constructed.", this.getClass()); 37 | } 38 | 39 | @Override 40 | public ActionResult route(BeatContext beat) { 41 | 42 | RouteBag bag = RouteBag.create(beat); 43 | 44 | for(Action action : actions) { 45 | RouteResult routeResult = action.matchAndInvoke(bag); 46 | if (routeResult.isSuccess()) 47 | return routeResult.getResult(); 48 | } 49 | 50 | return ActionResult.NULL; 51 | } 52 | 53 | List buildActions(Argo argo, Set> controllerClasses, Action staticAction) { 54 | 55 | Set controllers = getControllerInstances(argo, controllerClasses); 56 | return buildActions(controllers, staticAction); 57 | } 58 | 59 | private Set getControllerInstances(final Argo argo, Set> controllerClasses) { 60 | 61 | Iterable sets = Iterables.transform(controllerClasses, new Function, ArgoController>() { 62 | @Override 63 | public ArgoController apply(Class clazz) { 64 | 65 | // instance a controller 66 | ArgoController controller = argo.getInstance(clazz); 67 | // initialize the controller. 68 | controller.init(); 69 | 70 | return controller; 71 | } 72 | }); 73 | 74 | return ImmutableSet.copyOf(sets); 75 | } 76 | 77 | 78 | //TODO:static files actions. 79 | List buildActions(Set controllers, Action staticAction) { 80 | 81 | List actions = Lists.newArrayList(); 82 | actions.add(staticAction); 83 | 84 | for (ArgoController controller : controllers) { 85 | ControllerInfo controllerInfo = new ControllerInfo(controller); 86 | List subActions = controllerInfo.analyze(); 87 | 88 | for(ActionInfo newAction : subActions) 89 | merge(actions, MethodAction.create(newAction)); 90 | 91 | } 92 | 93 | return ImmutableList.copyOf(actions); 94 | } 95 | 96 | void merge(List actions, Action newAction) { 97 | 98 | for (int index = 0; index < actions.size(); index++) { 99 | Action action = actions.get(index); 100 | if(action.order() > newAction.order()) { 101 | actions.add(index, newAction); 102 | return; 103 | } 104 | } 105 | 106 | actions.add(newAction); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/MethodAction.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import java.util.Map; 4 | 5 | import com.bj58.argo.ActionResult; 6 | import com.bj58.argo.route.Action; 7 | import com.bj58.argo.interceptor.PostInterceptor; 8 | import com.bj58.argo.interceptor.PreInterceptor; 9 | import com.bj58.argo.route.RouteBag; 10 | import com.bj58.argo.route.RouteResult; 11 | import com.bj58.argo.thirdparty.AntPathMatcher; 12 | import com.bj58.argo.thirdparty.PathMatcher; 13 | import com.google.common.collect.Maps; 14 | 15 | public class MethodAction implements Action { 16 | 17 | public static MethodAction create(ActionInfo actionInfo) { 18 | return new MethodAction(actionInfo); 19 | } 20 | 21 | private final ActionInfo actionInfo; 22 | 23 | private final double order; 24 | 25 | private PathMatcher pathMatcher = new AntPathMatcher(); 26 | 27 | 28 | 29 | private MethodAction(ActionInfo actionInfo) { 30 | this.actionInfo = actionInfo; 31 | 32 | order = actionInfo.getOrder() 33 | + (10000.0d - actionInfo.getPathPattern().length())/100000.0d 34 | + (actionInfo.isPattern() ? 0.5d : 0d); 35 | } 36 | 37 | @Override 38 | public double order() { 39 | return order; 40 | } 41 | 42 | @Override 43 | public RouteResult matchAndInvoke(RouteBag bag) { 44 | 45 | if (!actionInfo.matchHttpMethod(bag)) 46 | return RouteResult.unMatch(); 47 | 48 | Map uriTemplateVariables = Maps.newHashMap(); 49 | 50 | boolean match = actionInfo.match(bag, uriTemplateVariables); 51 | if (!match) 52 | return RouteResult.unMatch(); 53 | 54 | // PreIntercept 55 | for(PreInterceptor preInterceptor : actionInfo.getPreInterceptors()) { 56 | ActionResult actionResult = preInterceptor.preExecute(bag.getBeat()); 57 | if (ActionResult.NULL != actionResult) 58 | return RouteResult.invoked(actionResult); 59 | } 60 | 61 | ActionResult actionResult = actionInfo.invoke(uriTemplateVariables); 62 | 63 | // PostIntercept 64 | for(PostInterceptor postInterceptor : actionInfo.getPostInterceptors()) { 65 | actionResult = postInterceptor.postExecute(bag.getBeat(), actionResult); 66 | } 67 | 68 | return RouteResult.invoked(actionResult); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/StaticFilesAction.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.Argo; 5 | import com.bj58.argo.inject.ArgoSystem; 6 | import com.bj58.argo.route.Action; 7 | import com.bj58.argo.internal.actionresult.StaticActionResult; 8 | import com.bj58.argo.convention.GroupConvention; 9 | import com.bj58.argo.route.RouteBag; 10 | import com.bj58.argo.route.RouteResult; 11 | import com.bj58.argo.utils.Pair; 12 | import com.bj58.argo.utils.PathUtils; 13 | import com.bj58.argo.utils.TouchTimer; 14 | import com.google.common.base.Preconditions; 15 | import com.google.common.collect.ImmutableSet; 16 | import com.google.common.collect.Lists; 17 | import com.google.common.collect.Sets; 18 | 19 | import javax.inject.Inject; 20 | import javax.inject.Singleton; 21 | import javax.servlet.ServletContext; 22 | import java.io.File; 23 | import java.util.Deque; 24 | import java.util.HashSet; 25 | import java.util.Set; 26 | import java.util.concurrent.Executor; 27 | 28 | /** 29 | * 对静态文件处理,把所有静态文件名保存在set中,如何精确匹配,表明当前请求就是静态文件 30 | * 31 | */ 32 | @Singleton 33 | public class StaticFilesAction implements Action { 34 | 35 | /** 36 | * 静态文件名set 37 | */ 38 | private Set staticFiles = Sets.newHashSet(); 39 | 40 | /** 41 | * 不允许访问的文件或文件夹 42 | */ 43 | private final Set forbitPath = ImmutableSet.of("/WEB-INF"); 44 | 45 | /** 46 | * 定时获取静态文件更新,但不需要另外的定时线程 47 | */ 48 | private final TouchTimer timer; 49 | 50 | private final StaticActionResult.Factory staticFactory; 51 | 52 | @Inject 53 | public StaticFilesAction( 54 | ServletContext servletContext 55 | , StaticActionResult.Factory staticFactory 56 | , @ArgoSystem final Executor executor 57 | ) { 58 | 59 | this.staticFactory = staticFactory; 60 | 61 | final File staticResourcesFolder = new File(servletContext.getRealPath("/")); 62 | 63 | 64 | Runnable findFiles = new Runnable() { 65 | @Override 66 | public void run() { 67 | staticFiles = findFiles(staticResourcesFolder, staticFiles.size(), forbitPath); 68 | } 69 | }; 70 | 71 | timer = TouchTimer 72 | .build(60 * 1000, findFiles, executor); 73 | 74 | timer.immediateRun(); 75 | } 76 | 77 | @Override 78 | public double order() { 79 | return 100d; 80 | } 81 | 82 | @Override 83 | public RouteResult matchAndInvoke(RouteBag bag) { 84 | return RouteResult.invoked(match(bag)); 85 | } 86 | 87 | private ActionResult match(RouteBag bag) { 88 | 89 | String simplyPath = bag.getSimplyPath(); 90 | 91 | if (!exist(simplyPath)) return ActionResult.NULL; 92 | 93 | return staticFactory.create(simplyPath); 94 | 95 | } 96 | 97 | private boolean exist(String url) { 98 | timer.touch(); 99 | return staticFiles.contains(url); 100 | } 101 | 102 | Set findFiles(File directory, int cap, Set forbitPath) { 103 | 104 | Set staticFiles = new HashSet(cap); 105 | 106 | Deque> dirs = Lists.newLinkedList(); 107 | 108 | dirs.add(Pair.build(directory, "/")); 109 | 110 | while (dirs.size() > 0) { 111 | Pair pop = dirs.pop(); 112 | 113 | File[] files = pop.getKey().listFiles(); 114 | 115 | if (files == null) 116 | continue; 117 | 118 | for (File file : files) { 119 | String name = pop.getValue() + file.getName(); 120 | 121 | if (forbitPath.contains(name)) 122 | continue; 123 | 124 | if (file.isDirectory()) { 125 | dirs.push(Pair.build(file 126 | , name + '/')); 127 | continue; 128 | } 129 | 130 | staticFiles.add(name); 131 | } 132 | } 133 | 134 | return staticFiles; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/VelocityViewFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Properties; 6 | 7 | import javax.inject.Inject; 8 | import javax.inject.Singleton; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | import com.bj58.argo.*; 12 | import com.bj58.argo.controller.ViewFactory; 13 | import org.apache.velocity.Template; 14 | import org.apache.velocity.VelocityContext; 15 | import org.apache.velocity.context.Context; 16 | import org.apache.velocity.io.VelocityWriter; 17 | 18 | import org.apache.velocity.runtime.RuntimeInstance; 19 | 20 | @Singleton 21 | public class VelocityViewFactory implements ViewFactory { 22 | 23 | private final RuntimeInstance rtInstance; 24 | 25 | private final String suffix = ".html"; 26 | 27 | @Inject 28 | public VelocityViewFactory(Argo argo) { 29 | 30 | String viewFolder = viewFolderPath(argo); 31 | 32 | Properties ps = new Properties(); 33 | ps.setProperty("resource.loader", "file"); 34 | ps.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader"); 35 | ps.setProperty("file.resource.loader.path", viewFolder); 36 | ps.setProperty("file.resource.loader.cache", "false"); 37 | ps.setProperty("file.resource.loader.modificationCheckInterval", "2"); 38 | ps.setProperty("input.encoding", "UTF-8"); 39 | ps.setProperty("output.encoding", "UTF-8"); 40 | ps.setProperty("default.contentType", "text/html; charset=UTF-8"); 41 | ps.setProperty("velocimarco.library.autoreload", "true"); 42 | ps.setProperty("runtime.log.error.stacktrace", "false"); 43 | ps.setProperty("runtime.log.warn.stacktrace", "false"); 44 | ps.setProperty("runtime.log.info.stacktrace", "false"); 45 | ps.setProperty("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); 46 | ps.setProperty("runtime.log.logsystem.log4j.category", "velocity_log"); 47 | 48 | rtInstance = new RuntimeInstance(); 49 | 50 | try { 51 | rtInstance.init(ps); 52 | } catch (Exception e) { 53 | throw ArgoException.raise(e); 54 | } 55 | } 56 | 57 | private String viewFolderPath(Argo argo) { 58 | File parent = argo.currentFolder(); 59 | return new File(parent, "views").getAbsolutePath(); 60 | } 61 | // 62 | // private File getViewFolder(GroupConvention groupConvention) { 63 | // ClassLoader cl = Thread.currentThread().getContextClassLoader(); 64 | // 65 | // URL viewURL = cl.getResource("views/"); 66 | // try { 67 | // return new File(viewURL.toURI()); 68 | // } catch (URISyntaxException e) { 69 | // throw ArgoException.raise("folder: " + viewURL + " must exist!!!", e); 70 | // } 71 | // } 72 | 73 | @Override 74 | public ActionResult create(String viewName) { 75 | return new VelocityViewResult(this, viewName); 76 | } 77 | 78 | Template getTemplate(String viewName) { 79 | return rtInstance.getTemplate(viewName + suffix); 80 | } 81 | 82 | private static class VelocityViewResult implements ActionResult { 83 | 84 | private final VelocityViewFactory factory; 85 | 86 | private final String viewName; 87 | 88 | private VelocityViewResult(VelocityViewFactory factory, String viewName) { 89 | this.factory = factory; 90 | this.viewName = viewName; 91 | } 92 | 93 | @Override 94 | public void render(BeatContext beatContext) { 95 | 96 | Template template = factory.getTemplate(viewName); 97 | 98 | HttpServletResponse response = beatContext.getResponse(); 99 | response.setContentType("text/html;charset=\"UTF-8\""); 100 | response.setCharacterEncoding("UTF-8"); 101 | // init context: 102 | Context context = new VelocityContext(beatContext.getModel().getModel()); 103 | // render: 104 | VelocityWriter vw = null; 105 | try { 106 | vw = new VelocityWriter(response.getWriter()); 107 | template.merge(context, vw); 108 | vw.flush(); 109 | } catch (IOException e) { 110 | throw ArgoException.raise(e); 111 | } 112 | finally { 113 | if (vw != null) 114 | vw.recycle(null); 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/actionresult/StaticActionResult.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal.actionresult; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.Argo; 5 | import com.bj58.argo.ArgoException; 6 | import com.bj58.argo.BeatContext; 7 | import com.bj58.argo.utils.PathUtils; 8 | import com.google.inject.ImplementedBy; 9 | 10 | import javax.inject.Inject; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.File; 14 | 15 | /** 16 | * 17 | * 处理静态文件 18 | * 19 | * 20 | */ 21 | public class StaticActionResult { 22 | 23 | @ImplementedBy(DefaultFactory.class) 24 | public static interface Factory { 25 | ActionResult create(String simplyPath); 26 | } 27 | 28 | private static class DefaultFactory implements Factory { 29 | 30 | 31 | @Inject 32 | public DefaultFactory() { 33 | } 34 | 35 | @Override 36 | public ActionResult create(String simplyPath) { 37 | 38 | return new DefaultStaticResult(simplyPath); 39 | } 40 | } 41 | 42 | private static class DefaultStaticResult implements ActionResult { 43 | 44 | private final String simplyPath; 45 | 46 | public DefaultStaticResult(String simplyPath) { 47 | this.simplyPath = simplyPath; 48 | 49 | } 50 | 51 | @Override 52 | public void render(BeatContext beatContext) { 53 | 54 | HttpServletRequest request = beatContext.getRequest(); 55 | HttpServletResponse response = beatContext.getResponse(); 56 | 57 | try { 58 | // 交给web容器处理 59 | request.getRequestDispatcher(simplyPath).forward(request, response); 60 | } catch (Throwable e) { 61 | throw ArgoException 62 | .newBuilder(e) 63 | .addContextVariable("File", simplyPath) 64 | .build(); 65 | } 66 | 67 | } 68 | } 69 | 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/actionresult/StatusCodeActionResult.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal.actionresult; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.BeatContext; 5 | 6 | import javax.inject.Inject; 7 | import javax.inject.Named; 8 | import javax.inject.Singleton; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | /** 13 | * 14 | */ 15 | @Singleton 16 | public class StatusCodeActionResult { 17 | 18 | public final static ActionResult defaultSc404 = new ActionResult() { 19 | @Override 20 | public void render(BeatContext beatContext) { 21 | 22 | HttpServletResponse response = beatContext.getResponse(); 23 | try { 24 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 25 | } catch (IOException e) { 26 | //TODO:log 27 | e.printStackTrace(); 28 | } 29 | 30 | } 31 | }; 32 | 33 | public final static ActionResult defaultSc405 = new ActionResult() { 34 | @Override 35 | public void render(BeatContext beatContext) { 36 | 37 | HttpServletResponse response = beatContext.getResponse(); 38 | try { 39 | response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); 40 | } catch (IOException e) { 41 | //TODO:log 42 | e.printStackTrace(); 43 | } 44 | } 45 | }; 46 | 47 | @Inject 48 | @Named("HTTP_STATUS=404") 49 | ActionResult sc404; 50 | 51 | @Inject 52 | @Named("HTTP_STATUS=405") 53 | ActionResult sc405; 54 | 55 | public void render404(BeatContext beat) { 56 | sc404.render(beat); 57 | } 58 | 59 | public void render405(BeatContext beat) { 60 | sc405.render(beat); 61 | } 62 | 63 | public ActionResult getSc404() { 64 | return sc404; 65 | } 66 | 67 | public ActionResult getSc405() { 68 | return sc405; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/internal/actionresult/statuscode/ActionResults.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.internal.actionresult.statuscode; 2 | 3 | import com.bj58.argo.ArgoException; 4 | import com.bj58.argo.ActionResult; 5 | import com.bj58.argo.BeatContext; 6 | 7 | import javax.servlet.http.HttpServletResponse; 8 | import javax.servlet.http.HttpServletResponseWrapper; 9 | import java.io.IOException; 10 | 11 | /** 12 | * 13 | */ 14 | public class ActionResults { 15 | 16 | private ActionResults() {} 17 | 18 | public static ActionResult redirect(final String url) { 19 | return new ActionResult() { 20 | @Override 21 | public void render(BeatContext beatContext) { 22 | try { 23 | beatContext.getResponse().sendRedirect(url); 24 | } catch (IOException e) { 25 | 26 | throw ArgoException.newBuilder(e) 27 | .addContextVariable("redirect url:", url) 28 | .build(); 29 | } 30 | } 31 | }; 32 | } 33 | 34 | public static ActionResult redirect301(final String url) { 35 | return new ActionResult() { 36 | @Override 37 | public void render(BeatContext beatContext) { 38 | try { 39 | //fixMe: 需要判断是否是同一个schema等因素 40 | HttpServletResponse response = beatContext.getResponse(); 41 | response.setStatus(301); 42 | response.sendRedirect(url); 43 | } catch (IOException e) { 44 | throw ArgoException.newBuilder(e) 45 | .addContextVariable("redirect url:", url) 46 | .build(); 47 | } 48 | } 49 | }; 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/lifecycle/LifeCycleState.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.lifecycle; 2 | 3 | /** 4 | * 当前调用的状态枚举 5 | */ 6 | public enum LifeCycleState { 7 | 8 | /** 9 | * 开始 10 | */ 11 | START, 12 | 13 | /** 14 | * 路由 15 | */ 16 | ROUTE, 17 | 18 | /** 19 | * 函数执行 20 | */ 21 | INVOKE, 22 | 23 | /** 24 | * 页面呈现 25 | */ 26 | RENDER, 27 | 28 | /** 29 | * 析构处理 30 | */ 31 | DESTRUCT 32 | 33 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/lifecycle/Lifecycle.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.lifecycle; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.google.common.collect.Queues; 5 | 6 | import java.util.Deque; 7 | 8 | public class Lifecycle { 9 | 10 | /** 11 | * 状态 12 | */ 13 | // private LifeCycleState state = LifeCycleState.START; 14 | 15 | /** 16 | * 创建时间 17 | */ 18 | private final long birthTime = System.currentTimeMillis(); 19 | 20 | /** 21 | * 析构函数栈 22 | */ 23 | private final Deque destructs = Queues.newArrayDeque(); 24 | 25 | /** 26 | * push 一个当前请求的析构处理 27 | * @param destruct 析构处理 28 | */ 29 | public void pushDestruct(Destruct destruct) { 30 | destructs.push(destruct); 31 | } 32 | 33 | /** 34 | * pop 出一个当前析构处理 35 | * @return 栈上第一个析构处理 null 栈上没数据。 36 | */ 37 | public Destruct pollDestruct() { 38 | return destructs.poll(); 39 | } 40 | 41 | public long getBirthTime() { 42 | return birthTime; 43 | } 44 | 45 | /** 46 | * 当前调用 47 | */ 48 | public interface Destruct { 49 | void clean(BeatContext beatContext); 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/lifecycle/LifecycleEvent.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.lifecycle; 2 | 3 | 4 | public interface LifecycleEvent { 5 | void before(LifeCycleState state); 6 | 7 | void after(LifeCycleState state); 8 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/lifecycle/LifecycleEventsManager.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.lifecycle; 2 | 3 | import com.google.common.collect.ForwardingSet; 4 | import com.google.common.collect.Maps; 5 | 6 | import java.util.Collection; 7 | import java.util.LinkedHashSet; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | /** 12 | * TODO:这个现在不实现,留给下一版本完成。 13 | * 可以监控系统的性能,甚至可以实现节流器功能 14 | *

15 | * 用于管理生命周期中的事件 16 | * 每个事件以类的形式注册,在每个BeatContext的生命周期,会为每个事件类构造一个对象。 17 | * 18 | */ 19 | public interface LifecycleEventsManager { 20 | 21 | /** 22 | * 注册事件,绑定特定的BeatContext生命周期状态 23 | * 24 | * @param eventClass 事件类 25 | * @param states 绑定的生命周期状态 26 | */ 27 | void registerLifecycleEvent(Class eventClass, LifeCycleState... states); 28 | 29 | /** 30 | * 移除绑定的特定注册事件 31 | * 32 | * @param eventClass 需要移除的事件类 33 | * @param states 需要移除的绑定的生命周期状态 34 | */ 35 | void removeLifecycleEvent(Class eventClass, LifeCycleState... states); 36 | 37 | /** 38 | * 获得某个生命周期状态的所有事件类 39 | * 40 | * @param state 特定的生命周期状态 41 | * @return 需要通知的事件集合 42 | */ 43 | Set> raiseEvents(LifeCycleState state); 44 | 45 | public static class Default implements LifecycleEventsManager { 46 | 47 | private Map>> eventsMap = Maps.newHashMap(); 48 | 49 | public Default() { 50 | for (LifeCycleState state : LifeCycleState.values()) 51 | eventsMap.put(state, new ImmutableLinkedHashSet>()); 52 | 53 | } 54 | 55 | private ImmutableLinkedHashSet> get(LifeCycleState state) { 56 | return eventsMap.get(state); 57 | 58 | } 59 | 60 | private Set> delegate(LifeCycleState state) { 61 | return get(state).delegate(); 62 | 63 | } 64 | 65 | @Override 66 | public synchronized void registerLifecycleEvent(Class eventClass, LifeCycleState... states) { 67 | 68 | for (LifeCycleState state : states) 69 | delegate(state).add(eventClass); 70 | } 71 | 72 | @Override 73 | public synchronized void removeLifecycleEvent(Class eventClass, LifeCycleState... states) { 74 | for (LifeCycleState state : states) 75 | delegate(state).remove(eventClass); 76 | 77 | } 78 | 79 | @Override 80 | public Set> raiseEvents(LifeCycleState state) { 81 | return get(state); 82 | } 83 | } 84 | 85 | class ImmutableLinkedHashSet extends ForwardingSet { 86 | 87 | private Set delegate; 88 | 89 | public ImmutableLinkedHashSet() { 90 | this.delegate = new LinkedHashSet(); 91 | } 92 | 93 | @Override 94 | protected Set delegate() { 95 | return delegate; 96 | } 97 | 98 | 99 | /** 100 | * Guaranteed to throw an exception and leave the collection unmodified. 101 | * 102 | * @throws UnsupportedOperationException always 103 | */ 104 | @Override 105 | public final boolean add(E e) { 106 | throw new UnsupportedOperationException(); 107 | } 108 | 109 | /** 110 | * Guaranteed to throw an exception and leave the collection unmodified. 111 | * 112 | * @throws UnsupportedOperationException always 113 | */ 114 | @Override 115 | public final boolean remove(Object object) { 116 | throw new UnsupportedOperationException(); 117 | } 118 | 119 | /** 120 | * Guaranteed to throw an exception and leave the collection unmodified. 121 | * 122 | * @throws UnsupportedOperationException always 123 | */ 124 | @Override 125 | public final boolean addAll(Collection newElements) { 126 | throw new UnsupportedOperationException(); 127 | } 128 | 129 | /** 130 | * Guaranteed to throw an exception and leave the collection unmodified. 131 | * 132 | * @throws UnsupportedOperationException always 133 | */ 134 | @Override 135 | public final boolean removeAll(Collection oldElements) { 136 | throw new UnsupportedOperationException(); 137 | } 138 | 139 | /** 140 | * Guaranteed to throw an exception and leave the collection unmodified. 141 | * 142 | * @throws UnsupportedOperationException always 143 | */ 144 | @Override 145 | public final boolean retainAll(Collection elementsToKeep) { 146 | throw new UnsupportedOperationException(); 147 | } 148 | 149 | /** 150 | * Guaranteed to throw an exception and leave the collection unmodified. 151 | * 152 | * @throws UnsupportedOperationException always 153 | */ 154 | @Override 155 | public final void clear() { 156 | throw new UnsupportedOperationException(); 157 | } 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/logs/LogConfigure.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.logs; 2 | 3 | import com.bj58.argo.internal.DefaultLoggerFactory; 4 | import com.google.inject.ImplementedBy; 5 | 6 | /** 7 | * 对日志文件进行设置 8 | * 默认采用log4j 9 | * 10 | */ 11 | @ImplementedBy(DefaultLoggerFactory.DefaultLog4jConfigure.class) 12 | public interface LogConfigure { 13 | 14 | void configure(); 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/logs/Logger.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.logs; 2 | 3 | /** 4 | * Log日志接口 5 | * 6 | * @author Service Platform Architecture Team (spat@58.com) 7 | */ 8 | public interface Logger { 9 | 10 | /** 11 | * Log a message at the DEBUG level. 12 | * 13 | * @param msg the message string to be logged. 14 | */ 15 | void debug(String msg); 16 | 17 | /** 18 | * Log a message at the DEBUG level according to the specified format 19 | * and argument. 20 | *

21 | *

This form avoids superfluous object creation when the logger 22 | * is disabled for the DEBUG level.

23 | * 24 | * @param format the format string 25 | * @param arg the argument 26 | */ 27 | public void debug(String format, Object arg); 28 | 29 | /** 30 | * Log an exception at the DEBUG level with an accompanying message. 31 | * 32 | * @param msg the message accompanying the exception 33 | * @param t the exception to be logged 34 | */ 35 | void debug(String msg, Throwable t); 36 | 37 | /** 38 | * Log a message at the INFO level. 39 | * 40 | * @param msg the message string to be logged 41 | */ 42 | void info(String msg); 43 | 44 | /** 45 | * Log a message at the INFO level according to the specified format 46 | * and argument. 47 | *

48 | *

This form avoids superfluous object creation when the logger 49 | * is disabled for the INFO level.

50 | * 51 | * @param format the format string 52 | * @param arg the argument 53 | */ 54 | public void info(String format, Object arg); 55 | 56 | /** 57 | * Log an exception at the INFO level with an accompanying message. 58 | * 59 | * @param msg the message accompanying the exception 60 | * @param t the exception to be logged 61 | */ 62 | void info(String msg, Throwable t); 63 | 64 | /** 65 | * Log a message at the ERROR level. 66 | * 67 | * @param msg the message string to be logged 68 | */ 69 | void error(String msg); 70 | 71 | /** 72 | * Log an exception at the ERROR level. 73 | * 74 | * @param msg the message accompanying the exception 75 | * @param t the exception to log 76 | */ 77 | void error(String msg, Throwable t); 78 | 79 | /** 80 | * Log a message at the ERROR level according to the specified format 81 | * and argument. 82 | *

83 | *

This form avoids superfluous object creation when the logger 84 | * is disabled for the ERROR level.

85 | * 86 | * @param format the format string 87 | * @param arg the argument 88 | */ 89 | public void error(String format, Object arg); 90 | 91 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/logs/LoggerFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.logs; 2 | 3 | import com.bj58.argo.internal.DefaultLoggerFactory; 4 | import com.google.inject.ImplementedBy; 5 | 6 | @ImplementedBy(DefaultLoggerFactory.class) 7 | public interface LoggerFactory { 8 | 9 | /** 10 | * 11 | * @param name the name of the Logger to return 12 | * @return a Logger instance 13 | */ 14 | Logger getLogger(String name); 15 | 16 | Logger getLogger(Class clazz); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/route/Action.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.route; 2 | 3 | /** 4 | * 封装的action方法 5 | */ 6 | public interface Action { 7 | /** 8 | * 确定优先级,路由时根据优先级进行匹配 9 | * @return 优先级 10 | */ 11 | double order(); 12 | 13 | /** 14 | * 匹配并且执行 15 | * @param bag 当前路由信息 16 | * @return 匹配或执行的结果 17 | */ 18 | RouteResult matchAndInvoke(RouteBag bag); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/route/RouteBag.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.route; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.bj58.argo.utils.PathUtils; 5 | 6 | /** 7 | * 路由信息 8 | */ 9 | public class RouteBag { 10 | 11 | public static RouteBag create(BeatContext beat) { 12 | return new RouteBag(beat); 13 | } 14 | 15 | private final BeatContext beat; 16 | private final boolean isGet; 17 | private final boolean isPost; 18 | private final String path; 19 | private final String simplyPath; 20 | 21 | private RouteBag(BeatContext beat) { 22 | this.beat = beat; 23 | 24 | path = beat.getClient().getRelativeUrl(); 25 | simplyPath = PathUtils.simplyWithoutSuffix(path); 26 | 27 | String requestMethod = beat.getRequest().getMethod().toUpperCase(); 28 | isPost = "POST".equals(requestMethod); 29 | isGet = !isPost; 30 | } 31 | 32 | public BeatContext getBeat() { 33 | return beat; 34 | } 35 | 36 | public boolean isGet() { 37 | return isGet; 38 | } 39 | 40 | public boolean isPost() { 41 | return isPost; 42 | } 43 | 44 | public String getPath() { 45 | return path; 46 | } 47 | 48 | public String getSimplyPath() { 49 | return simplyPath; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/route/RouteResult.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.route; 2 | 3 | import com.bj58.argo.ActionResult; 4 | 5 | /** 6 | * 路由处理的结果 7 | */ 8 | public class RouteResult { 9 | 10 | public static RouteResult unMatch() { 11 | return new RouteResult(false, ActionResult.NULL); 12 | } 13 | 14 | public static RouteResult invoked(ActionResult result) { 15 | return new RouteResult(ActionResult.NULL != result, result); 16 | } 17 | 18 | private final boolean success; 19 | private final ActionResult result; 20 | 21 | private RouteResult(boolean success, ActionResult result) { 22 | this.success = success; 23 | this.result = result; 24 | } 25 | 26 | public boolean isSuccess() { 27 | return success; 28 | } 29 | 30 | public ActionResult getResult() { 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/route/Router.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.route; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.bj58.argo.ActionResult; 5 | import com.bj58.argo.internal.DefaultRouter; 6 | import com.google.inject.ImplementedBy; 7 | 8 | /** 9 | * 路由器,根据每个请求的url进行匹配找到合适的 10 | * @see Action 11 | * 来执行 12 | */ 13 | @ImplementedBy(DefaultRouter.class) 14 | //@Singleton 15 | public interface Router { 16 | 17 | public ActionResult route(BeatContext beat); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/route/StaticActionAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.route; 2 | 3 | import com.google.inject.BindingAnnotation; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 用于Argo内部注入用 12 | * 13 | */ 14 | @BindingAnnotation 15 | @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface StaticActionAnnotation { 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/servlet/ArgoDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.servlet; 2 | 3 | import com.bj58.argo.BeatContext; 4 | import com.bj58.argo.internal.DefaultArgoDispatcher; 5 | import com.google.inject.ImplementedBy; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | /** 11 | * 12 | * 用于处理request请求调度的核心类 13 | * 14 | */ 15 | @ImplementedBy(DefaultArgoDispatcher.class) 16 | public interface ArgoDispatcher { 17 | 18 | void init(); 19 | 20 | void service(HttpServletRequest request, HttpServletResponse response); 21 | 22 | void destroy(); 23 | 24 | public HttpServletRequest currentRequest(); 25 | 26 | public HttpServletResponse currentResponse(); 27 | 28 | BeatContext currentBeatContext(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/servlet/ArgoDispatcherFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.servlet; 2 | 3 | import com.bj58.argo.Argo; 4 | import com.bj58.argo.convention.GroupConvention; 5 | import com.bj58.argo.convention.GroupConventionFactory; 6 | 7 | import javax.servlet.ServletContext; 8 | 9 | 10 | public class ArgoDispatcherFactory { 11 | 12 | public static ArgoDispatcher create(ServletContext servletContext){ 13 | 14 | // xxx:这是一处硬编码 15 | GroupConvention groupConvention = GroupConventionFactory.getGroupConvention(); 16 | 17 | return Argo.instance.init(servletContext, groupConvention); 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/servlet/ArgoFilter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.servlet; 2 | 3 | import javax.servlet.*; 4 | import javax.servlet.annotation.WebFilter; 5 | import javax.servlet.annotation.WebInitParam; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.io.IOException; 9 | 10 | /** 11 | * 利用Filter来实行调度 12 | */ 13 | @WebFilter(urlPatterns = {"/*"}, 14 | dispatcherTypes = {DispatcherType.REQUEST}, 15 | initParams = {@WebInitParam(name = "encoding", value = "UTF-8")} 16 | ) 17 | public class ArgoFilter implements Filter { 18 | 19 | private ArgoDispatcher dispatcher; 20 | 21 | @Override 22 | public void init(FilterConfig filterConfig) throws ServletException { 23 | 24 | 25 | ServletContext servletContext = filterConfig.getServletContext(); 26 | 27 | try { 28 | dispatcher = ArgoDispatcherFactory.create(servletContext); 29 | dispatcher.init(); 30 | } catch (Exception e) { 31 | 32 | servletContext.log("failed to argo initialize, system exit!!!", e); 33 | System.exit(1); 34 | 35 | } 36 | 37 | } 38 | 39 | @Override 40 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 41 | 42 | HttpServletRequest httpReq = (HttpServletRequest) request; 43 | HttpServletResponse httpResp = (HttpServletResponse) response; 44 | 45 | dispatcher.service(httpReq, httpResp); 46 | 47 | } 48 | 49 | @Override 50 | public void destroy() { 51 | dispatcher.destroy(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/AntPathStringMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.thirdparty; 22 | 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.regex.Matcher; 27 | import java.util.regex.Pattern; 28 | 29 | /** 30 | * Ant-style的路径匹配工具类 31 | * 32 | * @author Service Platform Architecture Team (spat@58.com) 33 | */ 34 | class AntPathStringMatcher { 35 | 36 | private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{([^/]+?)\\}"); 37 | 38 | private static final String DEFAULT_VARIABLE_PATTERN = "(.*)"; 39 | 40 | private final Pattern pattern; 41 | 42 | private String str; 43 | 44 | private final List variableNames = new LinkedList(); 45 | 46 | private final Map uriTemplateVariables; 47 | 48 | /** Construct a new instance of the AntPatchStringMatcher. */ 49 | AntPathStringMatcher(String pattern, String str, Map uriTemplateVariables) { 50 | this.str = str; 51 | this.uriTemplateVariables = uriTemplateVariables; 52 | this.pattern = createPattern(pattern); 53 | } 54 | 55 | private Pattern createPattern(String pattern) { 56 | StringBuilder patternBuilder = new StringBuilder(); 57 | Matcher m = GLOB_PATTERN.matcher(pattern); 58 | int end = 0; 59 | while (m.find()) { 60 | patternBuilder.append(quote(pattern, end, m.start())); 61 | String match = m.group(); 62 | if ("?".equals(match)) { 63 | patternBuilder.append('.'); 64 | } 65 | else if ("*".equals(match)) { 66 | patternBuilder.append(".*"); 67 | } 68 | else if (match.startsWith("{") && match.endsWith("}")) { 69 | int colonIdx = match.indexOf(':'); 70 | if (colonIdx == -1) { 71 | patternBuilder.append(DEFAULT_VARIABLE_PATTERN); 72 | variableNames.add(m.group(1)); 73 | } 74 | else { 75 | String variablePattern = match.substring(colonIdx + 1, match.length() - 1); 76 | patternBuilder.append('('); 77 | patternBuilder.append(variablePattern); 78 | patternBuilder.append(')'); 79 | String variableName = match.substring(1, colonIdx); 80 | variableNames.add(variableName); 81 | } 82 | } 83 | end = m.end(); 84 | } 85 | patternBuilder.append(quote(pattern, end, pattern.length())); 86 | return Pattern.compile(patternBuilder.toString()); 87 | } 88 | 89 | private String quote(String s, int start, int end) { 90 | if (start == end) { 91 | return ""; 92 | } 93 | return Pattern.quote(s.substring(start, end)); 94 | } 95 | 96 | /** 97 | * Main entry point. 98 | * 99 | * @return true if the string matches against the pattern, or false otherwise. 100 | */ 101 | public boolean matchStrings() { 102 | Matcher matcher = pattern.matcher(str); 103 | if (matcher.matches()) { 104 | if (uriTemplateVariables != null) { 105 | for (int i = 1; i <= matcher.groupCount(); i++) { 106 | String name = this.variableNames.get(i - 1); 107 | String value = matcher.group(i); 108 | uriTemplateVariables.put(name, value); 109 | } 110 | } 111 | return true; 112 | } 113 | else { 114 | return false; 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/ClassUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.thirdparty; 22 | 23 | 24 | import com.google.common.base.Preconditions; 25 | 26 | import java.io.File; 27 | import java.io.FileFilter; 28 | import java.io.IOException; 29 | import java.net.JarURLConnection; 30 | import java.net.URL; 31 | import java.net.URLDecoder; 32 | import java.util.ArrayList; 33 | import java.util.Enumeration; 34 | import java.util.LinkedHashSet; 35 | import java.util.List; 36 | import java.util.Set; 37 | import java.util.jar.JarEntry; 38 | import java.util.jar.JarFile; 39 | 40 | 41 | 42 | /** 43 | * 44 | * ClassUtil 45 | * 46 | * 扫描指定包(包括jar)下的class文件
47 | * 48 | * @author Service Platform Architecture Team (spat@58.com) 49 | */ 50 | public class ClassUtil { 51 | 52 | /** 53 | * Return all interfaces that the given class implements as array, 54 | * including ones implemented by superclasses. 55 | *

If the class itself is an interface, it gets returned as sole interface. 56 | * @param clazz the class to analyze for interfaces 57 | * @return all interfaces that the given object implements as array 58 | */ 59 | public static Class[] getAllInterfacesForClass(Class clazz) { 60 | return getAllInterfacesForClass(clazz, null); 61 | } 62 | /** 63 | * Return all interfaces that the given class implements as array, 64 | * including ones implemented by superclasses. 65 | *

If the class itself is an interface, it gets returned as sole interface. 66 | * @param clazz the class to analyze for interfaces 67 | * @param classLoader the ClassLoader that the interfaces need to be visible in 68 | * (may be null when accepting all declared interfaces) 69 | * @return all interfaces that the given object implements as array 70 | */ 71 | public static Class[] getAllInterfacesForClass(Class clazz, ClassLoader classLoader) { 72 | Set ifcs = getAllInterfacesForClassAsSet(clazz, classLoader); 73 | return ifcs.toArray(new Class[ifcs.size()]); 74 | } 75 | /** 76 | * Return all interfaces that the given class implements as Set, 77 | * including ones implemented by superclasses. 78 | *

If the class itself is an interface, it gets returned as sole interface. 79 | * @param clazz the class to analyze for interfaces 80 | * @param classLoader the ClassLoader that the interfaces need to be visible in 81 | * (may be null when accepting all declared interfaces) 82 | * @return all interfaces that the given object implements as Set 83 | */ 84 | public static Set getAllInterfacesForClassAsSet(Class clazz, ClassLoader classLoader) { 85 | Preconditions.checkNotNull(clazz, "Class must not be null"); 86 | if (clazz.isInterface() && isVisible(clazz, classLoader)) { 87 | return Collections.singleton(clazz); 88 | } 89 | Set interfaces = new LinkedHashSet(); 90 | while (clazz != null) { 91 | Class[] ifcs = clazz.getInterfaces(); 92 | for (Class ifc : ifcs) { 93 | interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader)); 94 | } 95 | clazz = clazz.getSuperclass(); 96 | } 97 | return interfaces; 98 | } 99 | 100 | 101 | /** 102 | * Check whether the given class is visible in the given ClassLoader. 103 | * @param clazz the class to check (typically an interface) 104 | * @param classLoader the ClassLoader to check against (may be null, 105 | * in which case this method will always return true) 106 | */ 107 | public static boolean isVisible(Class clazz, ClassLoader classLoader) { 108 | if (classLoader == null) { 109 | return true; 110 | } 111 | try { 112 | Class actualClass = classLoader.loadClass(clazz.getName()); 113 | return (clazz == actualClass); 114 | // Else: different interface class found... 115 | } 116 | catch (ClassNotFoundException ex) { 117 | // No interface class found... 118 | return false; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/HttpUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | package com.bj58.argo.thirdparty; 23 | 24 | import javax.servlet.http.HttpServletRequest; 25 | 26 | /** 27 | * @author Service Platform Architecture Team (spat@58.com) 28 | */ 29 | public class HttpUtils { 30 | 31 | /** 32 | * Part of HTTP content type header. 33 | */ 34 | public static final String MULTIPART = "multipart/"; 35 | 36 | /** 37 | * Utility method that determines whether the currentRequest contains multipart 38 | * content. 39 | * 40 | * @param request The servlet currentRequest to be evaluated. Must be non-null. 41 | * 42 | * @return true if the currentRequest is multipart; 43 | * false otherwise. 44 | * 45 | * @author Sean C. Sullivan 46 | */ 47 | public static final boolean isMultipartContent( 48 | HttpServletRequest request) { 49 | if (!"post".equals(request.getMethod().toLowerCase())) { 50 | return false; 51 | } 52 | String contentType = request.getContentType(); 53 | if (contentType == null) { 54 | return false; 55 | } 56 | if (contentType.toLowerCase().startsWith(MULTIPART)) { 57 | return true; 58 | } 59 | return false; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/jetty/ByteArrayOutputStream2.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.thirdparty.jetty; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.nio.charset.Charset; 5 | 6 | /* ------------------------------------------------------------ */ 7 | /** ByteArrayOutputStream with public internals 8 | 9 | * 10 | */ 11 | public class ByteArrayOutputStream2 extends ByteArrayOutputStream 12 | { 13 | public ByteArrayOutputStream2(){super();} 14 | public ByteArrayOutputStream2(int size){super(size);} 15 | public byte[] getBuf(){return buf;} 16 | public int getCount(){return count;} 17 | public void setCount(int count){this.count = count;} 18 | 19 | public void reset(int minSize) 20 | { 21 | reset(); 22 | if (buf.lengthm) 39 | return new String(buf,m,pos-m,StringUtil.__UTF8_CHARSET); 40 | 41 | return null; 42 | } 43 | 44 | if (b=='\r') 45 | { 46 | int p=pos; 47 | 48 | // if we have seen CRLF before, hungrily consume LF 49 | if (_seenCRLF && pos0) 94 | { 95 | _skipLF=false; 96 | if (_seenCRLF) 97 | { 98 | int b = super.read(); 99 | if (b==-1) 100 | return -1; 101 | 102 | if (b!='\n') 103 | { 104 | buf[off]=(byte)(0xff&b); 105 | return 1+super.read(buf,off+1,len-1); 106 | } 107 | } 108 | } 109 | 110 | return super.read(buf,off,len); 111 | } 112 | 113 | 114 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/jetty/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.thirdparty.jetty; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | 6 | /** Fast String Utilities. 7 | * 8 | * These string utilities provide both conveniance methods and 9 | * performance improvements over most standard library versions. The 10 | * main aim of the optimizations is to avoid object creation unless 11 | * absolutely required. 12 | * 13 | * 14 | */ 15 | public class StringUtil 16 | { 17 | private final static StringMap CHARSETS= new StringMap(true); 18 | 19 | public static final String ALL_INTERFACES="0.0.0.0"; 20 | public static final String CRLF="\015\012"; 21 | public static final String __LINE_SEPARATOR= 22 | System.getProperty("line.separator","\n"); 23 | 24 | public static final String __ISO_8859_1="ISO-8859-1"; 25 | public final static String __UTF8="UTF-8"; 26 | public final static String __UTF16="UTF-16"; 27 | 28 | public final static Charset __UTF8_CHARSET; 29 | public final static Charset __ISO_8859_1_CHARSET; 30 | public final static Charset __UTF16_CHARSET; 31 | 32 | static 33 | { 34 | __UTF8_CHARSET=Charset.forName(__UTF8); 35 | __ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1); 36 | __UTF16_CHARSET=Charset.forName(__UTF16); 37 | 38 | CHARSETS.put("UTF-8",__UTF8); 39 | CHARSETS.put("UTF8",__UTF8); 40 | CHARSETS.put("UTF-16",__UTF16); 41 | CHARSETS.put("UTF16",__UTF16); 42 | CHARSETS.put("ISO-8859-1",__ISO_8859_1); 43 | CHARSETS.put("ISO_8859_1",__ISO_8859_1); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/jetty/Utf8StringBuffer.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.thirdparty.jetty; 2 | /* ------------------------------------------------------------ */ 3 | /** 4 | * UTF-8 StringBuffer. 5 | * 6 | * This class wraps a standard {@link java.lang.StringBuffer} and provides methods to append 7 | * UTF-8 encoded bytes, that are converted into characters. 8 | * 9 | * This class is stateful and up to 4 calls to {@link #append(byte)} may be needed before 10 | * state a character is appended to the string buffer. 11 | * 12 | * The UTF-8 decoding is done by this class and no additional buffers or Readers are used. 13 | * The UTF-8 code was inspired by http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ 14 | */ 15 | public class Utf8StringBuffer extends Utf8Appendable 16 | { 17 | final StringBuffer _buffer; 18 | 19 | public Utf8StringBuffer() 20 | { 21 | super(new StringBuffer()); 22 | _buffer = (StringBuffer)_appendable; 23 | } 24 | 25 | public Utf8StringBuffer(int capacity) 26 | { 27 | super(new StringBuffer(capacity)); 28 | _buffer = (StringBuffer)_appendable; 29 | } 30 | 31 | @Override 32 | public int length() 33 | { 34 | return _buffer.length(); 35 | } 36 | 37 | @Override 38 | public void reset() 39 | { 40 | super.reset(); 41 | _buffer.setLength(0); 42 | } 43 | 44 | public StringBuffer getStringBuffer() 45 | { 46 | checkState(); 47 | return _buffer; 48 | } 49 | 50 | @Override 51 | public String toString() 52 | { 53 | checkState(); 54 | return _buffer.toString(); 55 | } 56 | } -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/thirdparty/jetty/Utf8StringBuilder.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.thirdparty.jetty; 2 | /* ------------------------------------------------------------ */ 3 | /** UTF-8 StringBuilder. 4 | * 5 | * This class wraps a standard {@link java.lang.StringBuilder} and provides methods to append 6 | * UTF-8 encoded bytes, that are converted into characters. 7 | * 8 | * This class is stateful and up to 4 calls to {@link #append(byte)} may be needed before 9 | * state a character is appended to the string buffer. 10 | * 11 | * The UTF-8 decoding is done by this class and no additional buffers or Readers are used. 12 | * The UTF-8 code was inspired by http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ 13 | * 14 | */ 15 | public class Utf8StringBuilder extends Utf8Appendable 16 | { 17 | final StringBuilder _buffer; 18 | 19 | public Utf8StringBuilder() 20 | { 21 | super(new StringBuilder()); 22 | _buffer=(StringBuilder)_appendable; 23 | } 24 | 25 | public Utf8StringBuilder(int capacity) 26 | { 27 | super(new StringBuilder(capacity)); 28 | _buffer=(StringBuilder)_appendable; 29 | } 30 | 31 | @Override 32 | public int length() 33 | { 34 | return _buffer.length(); 35 | } 36 | 37 | @Override 38 | public void reset() 39 | { 40 | super.reset(); 41 | _buffer.setLength(0); 42 | } 43 | 44 | public StringBuilder getStringBuilder() 45 | { 46 | checkState(); 47 | return _buffer; 48 | } 49 | 50 | @Override 51 | public String toString() 52 | { 53 | checkState(); 54 | return _buffer.toString(); 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/NetUtils.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils; 2 | 3 | import com.bj58.argo.ArgoException; 4 | import sun.net.util.IPAddressUtil; 5 | 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | 9 | public class NetUtils { 10 | 11 | private NetUtils() {} 12 | 13 | 14 | /** 15 | * 将ip地址由文本转换为byte数组 16 | * @param ipText 17 | * @return 18 | */ 19 | public static byte[] getDigitalFromText(String ipText) { 20 | byte[] ip = IPAddressUtil.textToNumericFormatV4(ipText); 21 | 22 | if (ip != null) 23 | return ip; 24 | 25 | ip = IPAddressUtil.textToNumericFormatV6(ipText); 26 | 27 | if (ip != null) 28 | return ip; 29 | 30 | throw ArgoException.raise(new UnknownHostException("[" + ipText + "]")); 31 | } 32 | 33 | public static InetAddress getInetAddressFromText(String ipText) { 34 | byte[] ip = getDigitalFromText(ipText); 35 | 36 | try { 37 | return InetAddress.getByAddress(ip); 38 | } catch (UnknownHostException e) { 39 | throw ArgoException.raise(new UnknownHostException("[" + ipText + "]")); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/OnlyOnceCondition.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils; 2 | 3 | import com.bj58.argo.ArgoException; 4 | 5 | import java.util.concurrent.atomic.AtomicBoolean; 6 | 7 | /** 8 | * 保证只执行一次 9 | * @author renjun 10 | */ 11 | public class OnlyOnceCondition { 12 | 13 | public static OnlyOnceCondition create(String message) { 14 | return new OnlyOnceCondition(message); 15 | } 16 | 17 | private final String message; 18 | private OnlyOnceCondition(String message) { 19 | this.message = message; 20 | } 21 | 22 | private final AtomicBoolean hasChecked = new AtomicBoolean(false); 23 | public void check() { 24 | if (!hasChecked.compareAndSet(false, true)) 25 | throw ArgoException 26 | .newBuilder(message) 27 | .build(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils; 2 | 3 | /** 4 | * @author renjun 5 | */ 6 | public class Pair { 7 | 8 | public static Pair build(K k, V v) { 9 | return new Pair(k, v); 10 | } 11 | 12 | private final K key; 13 | private final V value; 14 | 15 | public Pair(K k, V v) { 16 | this.key = k; 17 | this.value = v; 18 | } 19 | 20 | public K getKey() { 21 | return this.key; 22 | } 23 | 24 | public V getValue() { 25 | return this.value; 26 | } 27 | 28 | public java.lang.String toString() { 29 | return "Pair " + key + ": " + value; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/TouchTimer.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.atomic.AtomicBoolean; 5 | 6 | /** 7 | * 8 | * 一个不需要定时线程的定时器,减少线程量 9 | * 10 | * @author renjun 11 | */ 12 | public class TouchTimer { 13 | 14 | private final long interval; 15 | 16 | private final Runnable run; 17 | 18 | private final Executor executor; 19 | 20 | private volatile long lastTime = 0; 21 | private AtomicBoolean isRun = new AtomicBoolean(false); 22 | 23 | public static TouchTimer build(long interval, Runnable run, Executor executor) { 24 | return new TouchTimer(interval, run, executor); 25 | } 26 | 27 | public TouchTimer(long interval, Runnable run, Executor executor) { 28 | this.interval = interval; 29 | this.run = run; 30 | this.executor = executor; 31 | } 32 | 33 | public void touch() { 34 | 35 | long time = System.currentTimeMillis(); 36 | if (isRun.get()) 37 | return; 38 | 39 | if (time - lastTime < interval) 40 | return; 41 | 42 | execute(); 43 | 44 | lastTime = time; 45 | 46 | } 47 | 48 | public void execute() { 49 | 50 | if(!isRun.compareAndSet(false, true)) 51 | return; 52 | 53 | executor.execute(new Runnable() { 54 | @Override 55 | public void run() { 56 | immediateRun(); 57 | } 58 | }); 59 | 60 | } 61 | 62 | public void immediateRun() { 63 | try { 64 | if (isRun.get()) 65 | return; 66 | 67 | executor.execute(run); 68 | } finally { 69 | lastTime = System.currentTimeMillis(); 70 | isRun.set(false); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/BooleanConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Boolean. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class BooleanConverter implements Converter { 9 | 10 | public Boolean convert(String s) { 11 | return Boolean.parseBoolean(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/ByteConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Byte. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class ByteConverter implements Converter { 9 | 10 | public Byte convert(String s) { 11 | return Byte.parseByte(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/CharacterConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Character. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class CharacterConverter implements Converter { 9 | 10 | public Character convert(String s) { 11 | if (s.length()==0) 12 | throw new IllegalArgumentException("Cannot convert empty string to char."); 13 | return s.charAt(0); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/Converter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to any given type. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | * 8 | * @param Generic type of converted result. 9 | */ 10 | public interface Converter { 11 | 12 | /** 13 | * Convert a not-null String to specified object. 14 | */ 15 | T convert(String s); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/ConverterFactory.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Factory for all converters. 8 | * 9 | * fixMe: 可以改成注入 10 | * 11 | * @author Michael Liao (askxuefeng@gmail.com) 12 | */ 13 | public class ConverterFactory { 14 | 15 | // private static final Log log = LogFactory.getLog(ConverterFactory.class); 16 | 17 | private Map, Converter> map = new HashMap, Converter>(); 18 | 19 | public ConverterFactory() { 20 | loadInternal(); 21 | } 22 | 23 | void loadInternal() { 24 | 25 | Converter c = new StringConverter(); 26 | map.put(String.class, c); 27 | 28 | c = new BooleanConverter(); 29 | map.put(boolean.class, c); 30 | map.put(Boolean.class, c); 31 | 32 | c = new CharacterConverter(); 33 | map.put(char.class, c); 34 | map.put(Character.class, c); 35 | 36 | c = new ByteConverter(); 37 | map.put(byte.class, c); 38 | map.put(Byte.class, c); 39 | 40 | c = new ShortConverter(); 41 | map.put(short.class, c); 42 | map.put(Short.class, c); 43 | 44 | c = new IntegerConverter(); 45 | map.put(int.class, c); 46 | map.put(Integer.class, c); 47 | 48 | c = new LongConverter(); 49 | map.put(long.class, c); 50 | map.put(Long.class, c); 51 | 52 | c = new FloatConverter(); 53 | map.put(float.class, c); 54 | map.put(Float.class, c); 55 | 56 | c = new DoubleConverter(); 57 | map.put(double.class, c); 58 | map.put(Double.class, c); 59 | } 60 | 61 | 62 | public boolean canConvert(Class clazz) { 63 | return clazz.equals(String.class) || map.containsKey(clazz); 64 | } 65 | 66 | public Object convert(Class clazz, String s) { 67 | Converter c = map.get(clazz); 68 | return c.convert(s); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/DoubleConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Double. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class DoubleConverter implements Converter { 9 | 10 | public Double convert(String s) { 11 | return Double.parseDouble(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/FloatConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Float. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class FloatConverter implements Converter { 9 | 10 | public Float convert(String s) { 11 | return Float.parseFloat(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/IntegerConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Integer. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class IntegerConverter implements Converter { 9 | 10 | public Integer convert(String s) { 11 | return Integer.parseInt(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/LongConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Long. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class LongConverter implements Converter { 9 | 10 | public Long convert(String s) { 11 | return Long.parseLong(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/ShortConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Short. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class ShortConverter implements Converter { 9 | 10 | public Short convert(String s) { 11 | return Short.parseShort(s); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/StringConverter.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.utils.converter; 2 | 3 | /** 4 | * Convert String to Integer. 5 | * 6 | * @author Michael Liao (askxuefeng@gmail.com) 7 | */ 8 | public class StringConverter implements Converter { 9 | 10 | public String convert(String s) { 11 | return s; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/com/bj58/argo/utils/converter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Package that contains all converters which convert java.lang.String to 3 | * specified object. 4 | */ 5 | package com.bj58.argo.utils.converter; 6 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/ArgoDispatcherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo; 22 | 23 | import org.testng.annotations.Test; 24 | 25 | /** 26 | * @author Service Platform Architecture Team (spat@58.com) 27 | */ 28 | public class ArgoDispatcherTest { 29 | 30 | // ArgoDispatcher dispatcher = ArgoDispatcher.instance; 31 | // 32 | // @Test 33 | // public void testInit() { 34 | // dispatcher.init(null); 35 | // } 36 | // 37 | // @Test(expectedExceptions = ArgoException.class) 38 | // public void testInitMore() { 39 | // dispatcher.init(null); 40 | // dispatcher.init(null); 41 | // } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/ArgoExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo; 22 | 23 | import org.testng.annotations.Test; 24 | import org.testng.Assert; 25 | 26 | /** 27 | * @author Service Platform Architecture Team (spat@58.com) 28 | */ 29 | public class ArgoExceptionTest { 30 | 31 | @Test 32 | public void testMessage() { 33 | ArgoException ex = ArgoException.newBuilder("This is a message.") 34 | .build(); 35 | 36 | Assert.assertEquals("This is a message.", ex.getMessage()); 37 | Assert.assertNull(ex.getCause()); 38 | } 39 | 40 | 41 | @Test 42 | public void testCause() { 43 | Throwable ta = new RuntimeException("runtime exception."); 44 | ArgoException ex = ArgoException.newBuilder(ta).build(); 45 | Assert.assertEquals("", ex.getMessage()); 46 | Assert.assertEquals(ta, ex.getCause()); 47 | } 48 | 49 | @Test 50 | public void testBoth() { 51 | Throwable ta = new RuntimeException(); 52 | String message = "This is a message."; 53 | 54 | ArgoException ex = ArgoException.newBuilder(message, ta) 55 | .build(); 56 | 57 | Assert.assertEquals(message, ex.getMessage()); 58 | Assert.assertEquals(ta, ex.getCause()); 59 | 60 | } 61 | 62 | @Test 63 | public void testContext() { 64 | ArgoException ex = ArgoException.newBuilder() 65 | .addContextVariable("url", "http://weibo.com/duoway/") 66 | .addContextVariable("email", "jun.ren@gmail.com") 67 | .build(); 68 | 69 | Assert.assertEquals("\ncontext: {url=http://weibo.com/duoway/, email=jun.ren@gmail.com}", ex.getMessage()); 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/ArgoFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo; 2 | 3 | import static org.mockito.Mockito.mock; 4 | 5 | import javax.servlet.ServletException; 6 | 7 | import org.testng.annotations.Test; 8 | 9 | 10 | public class ArgoFilterTest { 11 | 12 | @Test 13 | public void testInit() throws ServletException { 14 | // FilterConfig filterConfig = mock(FilterConfig.class); 15 | // 16 | //// GroupConventionAnnotation groupConventionAnnotation = mock(GroupConventionAnnotation.class); 17 | //// when(groupConventionAnnotation.groupConfigFolder()).thenReturn("/opt/argo"); 18 | //// when(groupConventionAnnotation.projectConfigFolder()).thenReturn("{groupConfigFolder}/{projectId}"); 19 | //// when(groupConventionAnnotation.projectLogFolder()).thenReturn("{groupConfigFolder}/logs/{projectId}"); 20 | //// when(groupConventionAnnotation.groupPackagesPrefix()).thenReturn("com.bj58.argo"); 21 | //// when(groupConventionAnnotation.projectConventionClass()).thenReturn("com.bj58.argo.MyProjectConvention"); 22 | //// when(groupConventionAnnotation.controllerPattern()).thenReturn("com\\.bj58\\..*\\.controllers\\..*Controller"); 23 | //// when(groupConventionAnnotation.viewsFolder()).thenReturn("/WEB-INF/classes/views/"); 24 | //// when(groupConventionAnnotation.staticResourcesFolder()).thenReturn("/WEB-INF/classes/static/"); 25 | // 26 | // ServletContext servletContext = mock(ServletContext.class); 27 | // when(filterConfig.getServletContext()).thenReturn(servletContext); 28 | // when(servletContext.getContextPath()).thenReturn("/oss/web/post.58.com"); 29 | // 30 | // 31 | // ArgoFilter argoFilter = new ArgoFilter(); 32 | // argoFilter.init(filterConfig); 33 | 34 | } 35 | 36 | 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/ArgoTest.java: -------------------------------------------------------------------------------- 1 | ///* 2 | //* Copyright Beijing 58 Information Technology Co.,Ltd. 3 | //* 4 | //* Licensed to the Apache Software Foundation (ASF) under one 5 | //* or more contributor license agreements. See the NOTICE file 6 | //* distributed with this work for additional information 7 | //* regarding copyright ownership. The ASF licenses this file 8 | //* to you under the Apache License, Version 2.0 (the 9 | //* "License"); you may not use this file except in compliance 10 | //* with the License. You may obtain a copy of the License at 11 | //* 12 | //* http://www.apache.org/licenses/LICENSE-2.0 13 | //* 14 | //* Unless required by applicable law or agreed to in writing, 15 | //* software distributed under the License is distributed on an 16 | //* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | //* KIND, either express or implied. See the License for the 18 | //* specific language governing permissions and limitations 19 | //* under the License. 20 | //*/ 21 | //package com.bj58.argo; 22 | // 23 | //import static org.mockito.Mockito.mock; 24 | // 25 | //import java.io.File; 26 | // 27 | //import javax.servlet.ServletContext; 28 | // 29 | //import org.testng.Assert; 30 | //import org.testng.annotations.Test; 31 | // 32 | //import com.bj58.argo.convention.GroupConvention; 33 | // 34 | ///** 35 | // * @author Service Platform Architecture Team (spat@58.com) 36 | // */ 37 | //public class ArgoTest { 38 | // 39 | //// @Test(expectedExceptions = ArgoException.class 40 | //// , expectedExceptionsMessageRegExp = "Argo has been initialized.") 41 | //// public void testInitMore() { 42 | //// Argo.instance.init(); 43 | //// } 44 | // @Test 45 | // public void testSingleton() { 46 | // Argo argo1 = Argo.instance; 47 | // Argo argo2 = Argo.instance; 48 | // 49 | // Assert.assertEquals(argo1, argo2); 50 | // } 51 | // 52 | // @Test(expectedExceptions=ArgoException.class,expectedExceptionsMessageRegExp="Argo has been initialized.") 53 | // public void testInitOnlyOnce() { 54 | // ServletContext servletContext = mock(ServletContext.class); 55 | // GroupConvention groupConvention = mock(GroupConvention.class); 56 | // Argo.instance.init(servletContext, groupConvention); 57 | // Argo.instance.init(servletContext, groupConvention); 58 | // } 59 | // 60 | // public static class MyGroupConvention implements GroupConvention { 61 | // 62 | // @Override 63 | // public File rootFolder() { 64 | // // TODO Auto-generated method stub 65 | // return null; 66 | // } 67 | // 68 | // @Override 69 | // public File logPath() { 70 | // // TODO Auto-generated method stub 71 | // return null; 72 | // } 73 | // 74 | // @Override 75 | // public File projectConfigFolder() { 76 | // // TODO Auto-generated method stub 77 | // return null; 78 | // } 79 | // 80 | // @Override 81 | // public String currentProjectId() { 82 | // // TODO Auto-generated method stub 83 | // return null; 84 | // } 85 | // 86 | // @Override 87 | // public void assemblyInject(AssemblyInjector injector) { 88 | // // TODO Auto-generated method stub 89 | // 90 | // } 91 | // 92 | // @Override 93 | // public File viewsFolder() { 94 | // // TODO Auto-generated method stub 95 | // return null; 96 | // } 97 | // 98 | // @Override 99 | // public File staticResourcesFolder() { 100 | // // TODO Auto-generated method stub 101 | // return null; 102 | // } 103 | // 104 | // } 105 | //} 106 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/HadesModuleTest.java: -------------------------------------------------------------------------------- 1 | ///* 2 | //* Copyright Beijing 58 Information Technology Co.,Ltd. 3 | //* 4 | //* Licensed to the Apache Software Foundation (ASF) under one 5 | //* or more contributor license agreements. See the NOTICE file 6 | //* distributed with this work for additional information 7 | //* regarding copyright ownership. The ASF licenses this file 8 | //* to you under the Apache License, Version 2.0 (the 9 | //* "License"); you may not use this file except in compliance 10 | //* with the License. You may obtain a copy of the License at 11 | //* 12 | //* http://www.apache.org/licenses/LICENSE-2.0 13 | //* 14 | //* Unless required by applicable law or agreed to in writing, 15 | //* software distributed under the License is distributed on an 16 | //* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | //* KIND, either express or implied. See the License for the 18 | //* specific language governing permissions and limitations 19 | //* under the License. 20 | //*/ 21 | //package com.bj58.argo; 22 | // 23 | //import BeatContext; 24 | //import GroupConvention; 25 | //import AssemblyInjector; 26 | //import ArgoModule; 27 | //import com.google.inject.Injector; 28 | //import org.testng.Assert; 29 | //import org.testng.annotations.Test; 30 | // 31 | //import javax.servlet.http.HttpServletRequest; 32 | //import java.io.File; 33 | // 34 | //import static org.mockito.Mockito.*; 35 | // 36 | ///** 37 | // * @author Service Platform Architecture Team (spat@58.com) 38 | // */ 39 | //public class HadesModuleTest { 40 | // 41 | // @Test 42 | // public void testModule() { 43 | // 44 | // Argo argo = mock(Argo.class); 45 | // GroupConvention groupConvention = mock(GroupConvention.class); 46 | // BeatContext beatContext = mock(BeatContext.class); 47 | // 48 | // HadesModule module = new HadesModule(argo, groupConvention); 49 | // 50 | // Injector injector = module.getInjector(); 51 | // 52 | // when(argo.beatContext()).thenReturn(beatContext); 53 | // 54 | // HttpServletRequest request = mock(HttpServletRequest.class); 55 | // when(argo.request()).thenReturn(request); 56 | // 57 | // Assert.assertEquals(module.provideBeatContext(), beatContext); 58 | // Assert.assertEquals(module.provideHttpServletRequest(), request); 59 | // 60 | // 61 | // BeatContext actualBeat = injector.getInstance(BeatContext.class); 62 | // Assert.assertEquals(actualBeat, beatContext); 63 | // 64 | // } 65 | // 66 | // 67 | // 68 | // 69 | // GroupConvention groupConvention = new GroupConvention() { 70 | // @Override 71 | // public File groupConfigFolder() { 72 | // return new File("/opt/argo"); 73 | // } 74 | // 75 | // @Override 76 | // public File projectLogFolder() { 77 | // return new File("/opt/argo/logs"); 78 | // } 79 | // 80 | // @Override 81 | // public File projectConfigFolder() { 82 | // return new File("/opt/argo/me"); 83 | // } 84 | // 85 | // @Override 86 | // public String currentProjectId() { 87 | // return "myprojectId"; 88 | // } 89 | // 90 | // @Override 91 | // public void assemblyInject(AssemblyInjector injector) { 92 | // 93 | // } 94 | // 95 | // @Override 96 | // public File viewsFolder() { 97 | // return new File("/opt/web/my/WEB-INF/classes/create"); 98 | // } 99 | // 100 | // @Override 101 | // public File staticResourcesFolder() { 102 | // return new File("/opt/web/my/WEB-INF/classes/static"); 103 | // } 104 | // }; 105 | //} 106 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/client/IpAddressUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.client; 22 | 23 | 24 | import com.google.common.net.InetAddresses; 25 | import org.testng.Assert; 26 | import org.testng.annotations.Test; 27 | import sun.net.util.IPAddressUtil; 28 | 29 | import java.net.Inet4Address; 30 | import java.net.InetAddress; 31 | import java.net.UnknownHostException; 32 | 33 | /** 34 | * @author Service Platform Architecture Team (spat@58.com) 35 | */ 36 | public class IpAddressUtilTest { 37 | 38 | @Test 39 | public void testIpV4() { 40 | 41 | byte[] ip = IPAddressUtil.textToNumericFormatV4("211.151.115.9"); 42 | 43 | Assert.assertEquals(ip, new byte[]{211 - 256, 151 - 256, 115, 9}); 44 | 45 | ip = IPAddressUtil.textToNumericFormatV4("bj.58.com"); 46 | 47 | Assert.assertNull(ip); 48 | } 49 | 50 | @Test 51 | public void test() { 52 | 53 | } 54 | 55 | @Test 56 | public void testIsPrivateAddress() throws UnknownHostException { 57 | // byte[] rawAddress = { 10, 0, 0, 5 }; 58 | // 59 | // Inet4Address inet4Address = (Inet4Address) InetAddress.getByAddress(rawAddress); 60 | // 61 | // System.out.println(inet4Address.isAnyLocalAddress()); 62 | // System.out.println(inet4Address.isSiteLocalAddress()); 63 | // 64 | // rawAddress = new byte[] { 192 - 256, 168 - 256, 0, 5 }; 65 | // 66 | // inet4Address = (Inet4Address) InetAddress.getByAddress(rawAddress); 67 | // 68 | // System.out.println(inet4Address.isAnyLocalAddress()); 69 | // System.out.println(inet4Address.isSiteLocalAddress()); 70 | // 71 | // rawAddress = new byte[] { 211 - 256, 151 - 256, 70, 5 }; 72 | // 73 | // inet4Address = (Inet4Address) InetAddress.getByAddress(rawAddress); 74 | // 75 | // System.out.println(inet4Address.isAnyLocalAddress()); 76 | // System.out.println(inet4Address.isSiteLocalAddress()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/convention/GroupConventionAnnotationTest.java: -------------------------------------------------------------------------------- 1 | //package com.bj58.argo.convention; 2 | // 3 | //import org.testng.Assert; 4 | // 5 | //import org.testng.annotations.Test; 6 | // 7 | //public class GroupConventionAnnotationTest { 8 | // 9 | // //采用注解默认值 10 | // @GroupConventionAnnotation 11 | // public static class AnnotationDefaultClass { 12 | // } 13 | // 14 | // @Test(description="default") 15 | // public void testDefaultAnnotation() { 16 | // GroupConventionAnnotation ga = AnnotationDefaultClass.class.getAnnotation(GroupConventionAnnotation.class); 17 | // Assert.assertEquals(ga.groupConfigFolder(),"/opt/argo"); 18 | // Assert.assertEquals(ga.projectConfigFolder(),"{groupConfigFolder}/{projectId}"); 19 | // Assert.assertEquals(ga.projectLogFolder(),"{groupConfigFolder}/logs/{projectId}"); 20 | // Assert.assertEquals(ga.groupPackagesPrefix(),"com.bj58.argo"); 21 | // Assert.assertEquals(ga.projectConventionClass(),"com.bj58.argo.MyProjectConvention"); 22 | // Assert.assertEquals(ga.controllerPattern(),"com\\.bj58\\..*\\.controllers\\..*Controller"); 23 | // Assert.assertEquals(ga.viewsFolder(),"/WEB-INF/classes/views/"); 24 | // Assert.assertEquals(ga.staticResourcesFolder(),"/WEB-INF/classes/static/"); 25 | // } 26 | // 27 | // //采用注解自定义值 28 | // @GroupConventionAnnotation( 29 | // groupConfigFolder ="rootFolderCustom", 30 | // projectConfigFolder ="configFolderCustom", 31 | // projectLogFolder ="logPathCustom", 32 | // groupPackagesPrefix ="packagesPrefixCustom", 33 | // projectConventionClass="projectConventionClassCustom", 34 | // controllerPattern="controllerPatternCustom", 35 | // viewsFolder="viewsFolderCustom", 36 | // staticResourcesFolder="staticResourcesFolderCustom" 37 | // ) 38 | // public static class AnnotationCustomClass { 39 | // 40 | // } 41 | // 42 | // @Test(description="custom") 43 | // public void testCustomAnnotation() { 44 | // GroupConventionAnnotation ga = AnnotationCustomClass.class.getAnnotation(GroupConventionAnnotation.class); 45 | // Assert.assertEquals(ga.groupConfigFolder(),"rootFolderCustom"); 46 | // Assert.assertEquals(ga.projectConfigFolder(),"configFolderCustom"); 47 | // Assert.assertEquals(ga.projectLogFolder(),"logPathCustom"); 48 | // Assert.assertEquals(ga.groupPackagesPrefix(),"packagesPrefixCustom"); 49 | // Assert.assertEquals(ga.projectConventionClass(),"projectConventionClassCustom"); 50 | // Assert.assertEquals(ga.controllerPattern(),"controllerPatternCustom"); 51 | // Assert.assertEquals(ga.viewsFolder(),"viewsFolderCustom"); 52 | // Assert.assertEquals(ga.staticResourcesFolder(),"staticResourcesFolderCustom"); 53 | // } 54 | // 55 | // 56 | // 57 | // 58 | //} 59 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/learn/ClassTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.learn; 22 | 23 | import org.testng.Assert; 24 | import org.testng.annotations.Test; 25 | 26 | import java.lang.annotation.Annotation; 27 | import java.lang.reflect.Field; 28 | import java.lang.reflect.Method; 29 | 30 | /** 31 | * @author Service Platform Architecture Team (spat@58.com) 32 | */ 33 | public class ClassTest { 34 | 35 | private String s = "abc"; 36 | 37 | @Test 38 | public void testAnnotation() { 39 | Annotation[] annotations = ClassTest.class.getAnnotations(); 40 | 41 | Assert.assertNotNull(annotations); 42 | Assert.assertEquals(0, annotations.length); 43 | 44 | Method[] methods = ClassTest.class.getMethods(); 45 | 46 | for (Method method : methods) { 47 | annotations = method.getAnnotations(); 48 | 49 | Assert.assertNotNull(annotations); 50 | // Assert.assertEquals(0, annotations.length); 51 | } 52 | } 53 | 54 | @Test 55 | public void testField() throws Exception { 56 | 57 | Class clazz = ClassTest.class; 58 | for(Field field : clazz.getDeclaredFields()) { 59 | if ("s".equals(field.getName())) { 60 | field.setAccessible(true); 61 | field.set(this, "xxxxxxxxxxxxxxxxxx"); 62 | } 63 | } 64 | 65 | System.out.println(this.s); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/learn/FileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.learn; 22 | 23 | import org.testng.annotations.Test; 24 | 25 | import java.io.File; 26 | 27 | /** 28 | * @author Service Platform Architecture Team (spat@58.com) 29 | */ 30 | public class FileTest { 31 | 32 | @Test 33 | public void testContain() { 34 | File src = new File("D:\\新建文件夹\\facade\\"); 35 | File src1 = new File("D:\\新建文件夹\\facade"); 36 | File dest = new File("D:/新建文件夹/facade/新建文件夹/aa"); 37 | File dest1 = new File("D:/新建文件夹/facadeXXXX/新建文件夹/aa"); 38 | 39 | System.out.println(dest.getAbsolutePath().indexOf(src.getAbsolutePath()) == 0); 40 | System.out.println(dest1.getAbsolutePath().indexOf(src.getAbsolutePath()) == 0); 41 | 42 | System.out.println(src.getAbsolutePath()); 43 | System.out.println(src1.getAbsolutePath()); 44 | System.out.println(dest.getAbsolutePath()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/learn/injector/InjectTest.java: -------------------------------------------------------------------------------- 1 | ///* 2 | //* Copyright Beijing 58 Information Technology Co.,Ltd. 3 | //* 4 | //* Licensed to the Apache Software Foundation (ASF) under one 5 | //* or more contributor license agreements. See the NOTICE file 6 | //* distributed with this work for additional information 7 | //* regarding copyright ownership. The ASF licenses this file 8 | //* to you under the Apache License, Version 2.0 (the 9 | //* "License"); you may not use this file except in compliance 10 | //* with the License. You may obtain a copy of the License at 11 | //* 12 | //* http://www.apache.org/licenses/LICENSE-2.0 13 | //* 14 | //* Unless required by applicable law or agreed to in writing, 15 | //* software distributed under the License is distributed on an 16 | //* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | //* KIND, either express or implied. See the License for the 18 | //* specific language governing permissions and limitations 19 | //* under the License. 20 | //*/ 21 | //package com.bj58.argo.learn.injector; 22 | // 23 | //import ArgoController; 24 | //import HadesModule; 25 | //import com.google.common.collect.Lists; 26 | //import com.google.common.collect.Sets; 27 | //import com.google.inject.Guice; 28 | //import com.google.inject.Injector; 29 | //import org.testng.annotations.Test; 30 | // 31 | ///** 32 | // * @author Service Platform Architecture Team (spat@58.com) 33 | // */ 34 | //public class InjectTest { 35 | // 36 | // @Test 37 | // public void test() { 38 | // Injector injector = Guice.createInjector(new HadesModule(Sets.>newLinkedHashSet())); 39 | // 40 | // C c = injector.getInstance(C.class); 41 | // c.test(); 42 | // } 43 | // 44 | // public static class C { 45 | // 46 | // public void test(){ 47 | // System.out.println("aaa"); 48 | // } 49 | // 50 | // } 51 | //} 52 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/learn/injector/ProvidersTest.java: -------------------------------------------------------------------------------- 1 | ///* 2 | //* Copyright Beijing 58 Information Technology Co.,Ltd. 3 | //* 4 | //* Licensed to the Apache Software Foundation (ASF) under one 5 | //* or more contributor license agreements. See the NOTICE file 6 | //* distributed with this work for additional information 7 | //* regarding copyright ownership. The ASF licenses this file 8 | //* to you under the Apache License, Version 2.0 (the 9 | //* "License"); you may not use this file except in compliance 10 | //* with the License. You may obtain a copy of the License at 11 | //* 12 | //* http://www.apache.org/licenses/LICENSE-2.0 13 | //* 14 | //* Unless required by applicable law or agreed to in writing, 15 | //* software distributed under the License is distributed on an 16 | //* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | //* KIND, either express or implied. See the License for the 18 | //* specific language governing permissions and limitations 19 | //* under the License. 20 | //*/ 21 | //package com.bj58.argo.learn.injector; 22 | // 23 | //import com.google.inject.AbstractModule; 24 | //import com.google.inject.Guice; 25 | //import com.google.inject.Injector; 26 | //import com.google.inject.Provides; 27 | //import org.testng.annotations.Test; 28 | // 29 | //import javax.inject.Inject; 30 | //import javax.inject.Singleton; 31 | // 32 | ///** 33 | // * @author Service Platform Architecture Team (spat@58.com) 34 | // */ 35 | //public class ProvidersTest { 36 | // 37 | // public final static Injector injector = Guice.createInjector(new MyModule()); 38 | // 39 | // 40 | // @Test 41 | // public void test() { 42 | // C1 c1 = injector.getInstance(C1.class); 43 | // 44 | // System.out.println("QQQQQQQQQQQQQQQQQQQQQQ"); 45 | // System.out.println(c1.c3().c2()); 46 | // } 47 | // 48 | // 49 | // 50 | // public static class MyModule extends AbstractModule { 51 | // 52 | // 53 | // 54 | // @Override 55 | // protected void configure() { 56 | // 57 | // 58 | // } 59 | // } 60 | // 61 | // public static class C1 { 62 | // 63 | // public C3 c3() { 64 | // return injector.getInstance(C3.class); 65 | // } 66 | // 67 | // 68 | // @Provides 69 | // @Singleton 70 | // public C2 providerC2() { 71 | // System.out.println("provider C2 1"); 72 | // C2 c2 = new C2(); 73 | // System.out.println("provider C2 2"); 74 | // 75 | // return c2; 76 | // } 77 | // 78 | // 79 | // } 80 | // 81 | // public static class C2 { 82 | // 83 | // public C2() { 84 | // System.out.println("XXXXXXXXXXXXXX"); 85 | // } 86 | // 87 | // final long time = System.currentTimeMillis(); 88 | // 89 | // public long getTime() { 90 | // return time; 91 | // } 92 | // 93 | // } 94 | // 95 | // 96 | // public static class C3 { 97 | // 98 | // private final C2 c2; 99 | // 100 | // @Inject 101 | // public C3(C2 c2) { 102 | // System.out.println("CCCCCC3"); 103 | // this.c2 = c2; 104 | // } 105 | // 106 | // public C2 c2() { 107 | // return c2; 108 | // } 109 | // 110 | // } 111 | // 112 | //} 113 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/logs/LoggerTest.java: -------------------------------------------------------------------------------- 1 | ///* 2 | //* Copyright Beijing 58 Information Technology Co.,Ltd. 3 | //* 4 | //* Licensed to the Apache Software Foundation (ASF) under one 5 | //* or more contributor license agreements. See the NOTICE file 6 | //* distributed with this work for additional information 7 | //* regarding copyright ownership. The ASF licenses this file 8 | //* to you under the Apache License, Version 2.0 (the 9 | //* "License"); you may not use this file except in compliance 10 | //* with the License. You may obtain a copy of the License at 11 | //* 12 | //* http://www.apache.org/licenses/LICENSE-2.0 13 | //* 14 | //* Unless required by applicable law or agreed to in writing, 15 | //* software distributed under the License is distributed on an 16 | //* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | //* KIND, either express or implied. See the License for the 18 | //* specific language governing permissions and limitations 19 | //* under the License. 20 | //*/ 21 | //package com.bj58.argo.logs; 22 | // 23 | //import com.google.inject.*; 24 | //import com.google.inject.matcher.Matchers; 25 | //import org.testng.annotations.Test; 26 | // 27 | //import javax.inject.Inject; 28 | // 29 | ///** 30 | // * @author Service Platform Architecture Team (spat@58.com) 31 | // */ 32 | //public class LoggerTest { 33 | // 34 | // private Module module = new AbstractModule() { 35 | // @Override 36 | // protected void configure() { 37 | // this.bindListener(Matchers.any(), new LoggerTypeListener()); 38 | // } 39 | // }; 40 | // 41 | // @Test 42 | // public void test() { 43 | // Injector injector = Guice.createInjector(module); 44 | // 45 | // CI c = injector.getInstance(CI.class); 46 | // 47 | // c.test(); 48 | // 49 | // 50 | // } 51 | // 52 | // @ImplementedBy(C.class) 53 | // public static interface CI { 54 | // void test(); 55 | // } 56 | // 57 | // public static class C implements CI{ 58 | // private Logger logger; 59 | // 60 | // 61 | //// private final Logger logger2; 62 | //// 63 | //// @Inject 64 | //// public C (Logger logger2) { 65 | //// this.logger2 = logger2; 66 | //// } 67 | // 68 | // public void test() { 69 | // System.out.println("log1"); 70 | // System.out.println(logger.toString()); 71 | // System.out.println("log2"); 72 | //// System.out.println(logger2.toString()); 73 | // } 74 | // } 75 | // 76 | //// private static class MyModule extends AbstractModule { 77 | //// 78 | //// @Override 79 | //// protected void configure() { 80 | //// 81 | //// } 82 | //// 83 | //// public 84 | //// } 85 | //} 86 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/route/PathMatcherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.route; 22 | 23 | import com.bj58.argo.thirdparty.AntPathMatcher; 24 | import com.bj58.argo.thirdparty.PathMatcher; 25 | import org.testng.Assert; 26 | import org.testng.annotations.Test; 27 | 28 | import java.util.Map; 29 | 30 | /** 31 | * @author Service Platform Architecture Team (spat@58.com) 32 | */ 33 | public class PathMatcherTest { 34 | 35 | @Test 36 | public void test() { 37 | PathMatcher pathMatcher = new AntPathMatcher(); 38 | 39 | String pattern = "/{a}/{b}/{c}"; 40 | 41 | String sample = "/aa/bb/cc"; 42 | 43 | Assert.assertTrue(pathMatcher.match(pattern, sample)); 44 | 45 | } 46 | 47 | 48 | @Test 49 | public void testPathMatch(){ 50 | PathMatcher pathMatcher = new AntPathMatcher(); 51 | String registeredPath = "/me/hello/{name}"; 52 | String url = "/me/hello/renjun"; 53 | Assert.assertTrue(pathMatcher.match(registeredPath, url)); 54 | 55 | Map values = pathMatcher.extractUriTemplateVariables(registeredPath, url); 56 | Assert.assertEquals(1, values.size()); 57 | Assert.assertEquals("renjun", values.get("name")); 58 | 59 | System.out.println("OK testpathMatch"); 60 | 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/test/TestBeatContextProvider.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.test; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | import java.util.Map; 6 | 7 | public class TestBeatContextProvider { 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/src/test/java/com/bj58/argo/utils/OnlyOnceConditionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo.utils; 22 | 23 | import com.bj58.argo.ArgoException; 24 | import org.testng.annotations.Test; 25 | 26 | /** 27 | * @author Service Platform Architecture Team (spat@58.com) 28 | */ 29 | public class OnlyOnceConditionTest { 30 | 31 | @Test 32 | public void testOnlyOnce(){ 33 | OnlyOnceCondition onlyOnce = OnlyOnceCondition.create("This is a test."); 34 | 35 | onlyOnce.check(); 36 | 37 | 38 | } 39 | 40 | @Test(expectedExceptions = ArgoException.class) 41 | public void testMore(){ 42 | OnlyOnceCondition onlyOnce = OnlyOnceCondition.create("This is a test."); 43 | 44 | onlyOnce.check(); 45 | 46 | onlyOnce.check(); 47 | 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/test/java/learn/ExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package learn; 22 | 23 | import org.testng.annotations.Test; 24 | 25 | /** 26 | * @author Service Platform Architecture Team (spat@58.com) 27 | */ 28 | public class ExceptionTest { 29 | 30 | @Test 31 | public void test() { 32 | Exception e1 = new Exception("e1"); 33 | // System.out.println("e1=================================="); 34 | // e1.printStackTrace(); 35 | 36 | // System.out.println("e2=================================="); 37 | 38 | Exception e2 = new Exception("e2",e1); 39 | // e2.printStackTrace(); 40 | 41 | // System.out.println("e3=================================="); 42 | 43 | Exception e3 = new MyException(e1); 44 | e3.printStackTrace(); 45 | } 46 | 47 | private static class MyException extends Exception { 48 | public MyException(Throwable e) { 49 | // super("My exception's message", e, false, false); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/src/test/java/learn/ExecuteLearn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package learn; 22 | 23 | import java.util.concurrent.CompletionService; 24 | import java.util.concurrent.Future; 25 | import java.util.concurrent.FutureTask; 26 | 27 | /** 28 | * @author Service Platform Architecture Team (spat@58.com) 29 | */ 30 | public class ExecuteLearn { 31 | 32 | public void testFuture() { 33 | CompletionService cs ; 34 | Future future; 35 | FutureTask ft; 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/test/java/learn/FileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | package learn; 23 | 24 | import java.io.File; 25 | import org.junit.Test; 26 | 27 | /** 28 | * @author Service Platform Architecture Team (spat@58.com) 29 | */ 30 | public class FileTest { 31 | 32 | @Test 33 | public void testFile() { 34 | String path = "/temp"; 35 | 36 | String path1 = path; 37 | File file = new File(path1); 38 | 39 | System.out.println(file.isAbsolute()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/test/java/learn/HashmapTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | package learn; 23 | 24 | import java.util.BitSet; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | import org.junit.Test; 29 | 30 | /** 31 | * @author Service Platform Architecture Team (spat@58.com) 32 | */ 33 | public class HashmapTest { 34 | 35 | @Test 36 | public void testTime() { 37 | long time = System.currentTimeMillis(); 38 | 39 | System.out.println(time); 40 | 41 | 42 | } 43 | 44 | @Test 45 | public void testadd() { 46 | Map m = new HashMap(); 47 | m.put(100, "a"); 48 | m.put(200, "b"); 49 | 50 | 51 | for(Map.Entry entry : m.entrySet()) { 52 | System.out.println(entry.getValue()); 53 | } 54 | } 55 | 56 | // public void testMethod() { 57 | // CA ca = null; 58 | // } 59 | // 60 | // public static class CA { 61 | // public String a() { 62 | // return null; 63 | // } 64 | // } 65 | // 66 | } 67 | -------------------------------------------------------------------------------- /core/src/test/java/learn/InjectorLearn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package learn; 22 | 23 | import com.google.inject.*; 24 | import com.google.inject.spi.TypeEncounter; 25 | import com.google.inject.spi.TypeListener; 26 | import org.testng.annotations.Test; 27 | 28 | import javax.inject.Inject; 29 | import java.lang.reflect.Constructor; 30 | 31 | /** 32 | * @author Service Platform Architecture Team (spat@58.com) 33 | */ 34 | public class InjectorLearn { 35 | 36 | 37 | public static class MyTypeListener implements TypeListener { 38 | 39 | @Override 40 | public void hear(TypeLiteral type, TypeEncounter encounter) { 41 | 42 | 43 | Class clazz = type.getRawType(); 44 | 45 | if (My.class != clazz) 46 | return; 47 | 48 | Constructor[] cs = clazz.getConstructors(); 49 | 50 | Constructor c = null; 51 | for(Constructor cn : cs) { 52 | if (cn.getAnnotation(Inject.class) != null) { 53 | c = cn; 54 | break; 55 | } 56 | } 57 | 58 | if (c == null) 59 | return; 60 | 61 | 62 | Class[] fs = c.getParameterTypes(); 63 | encounter.register(new MembersInjector() { 64 | @Override 65 | public void injectMembers(I instance) { 66 | long time = System.currentTimeMillis(); 67 | System.out.println("a" + time); 68 | } 69 | }); 70 | } 71 | } 72 | 73 | 74 | public static class My { 75 | private String a1; 76 | 77 | @Inject 78 | public My(String a) { 79 | this.a1 = a; 80 | } 81 | 82 | public void test() { 83 | System.out.println(a1); 84 | } 85 | } 86 | 87 | @Test 88 | public void testMy1() { 89 | Injector injector = Guice.createInjector(new Module() { 90 | @Override 91 | public void configure(Binder binder) { 92 | 93 | binder.bind(String.class).toInstance("xyz"); 94 | 95 | } 96 | }); 97 | 98 | My1 my1 = injector.getInstance(My1.class); 99 | my1.test(); 100 | 101 | My my = injector.getInstance(My.class); 102 | my.test(); 103 | } 104 | 105 | public static class My1 { 106 | private String a; 107 | 108 | 109 | public My1() { 110 | long time = System.currentTimeMillis(); 111 | a = String.valueOf(time); 112 | } 113 | 114 | public void test() { 115 | System.out.println(a); 116 | 117 | Thread.currentThread().getStackTrace(); 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /core/src/test/java/learn/LearnJssist.java: -------------------------------------------------------------------------------- 1 | package learn; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Modifier; 5 | 6 | import javassist.ClassClassPath; 7 | import javassist.ClassPool; 8 | import javassist.CtClass; 9 | import javassist.CtMethod; 10 | import javassist.NotFoundException; 11 | import javassist.bytecode.CodeAttribute; 12 | import javassist.bytecode.LocalVariableAttribute; 13 | import javassist.bytecode.MethodInfo; 14 | 15 | import org.junit.Test; 16 | 17 | 18 | 19 | 20 | public class LearnJssist { 21 | 22 | 23 | /** 24 | * 得到方法参数名称数组 25 | * 由于java没有提供获得参数名称的api,利用了javassist来实现 26 | * @return 27 | */ 28 | public String[] getMethodParamNames(Class clazz, String methodName) { 29 | Method method =null; 30 | try { 31 | ClassPool pool = ClassPool.getDefault(); 32 | 33 | 34 | pool.insertClassPath(new ClassClassPath(clazz)); 35 | 36 | CtClass cc = pool.get(clazz.getName()); 37 | 38 | //DEBUG, 函数名相同的方法重载的信息读不到 2011-03-21 39 | CtMethod cm = cc.getDeclaredMethod(method.getName()); 40 | 41 | //2011-03-21 42 | // String[] paramTypeNames = new String[method.getParameterTypes().length]; 43 | // for (int i = 0; i < paramTypes.length; i++) 44 | // paramTypeNames[i] = paramTypes[i].getName(); 45 | // CtMethod cm = cc.getDeclaredMethod(method.getName(), pool.get(new String[] {})); 46 | 47 | // 使用javaassist的反射方法获取方法的参数名 48 | MethodInfo methodInfo = cm.getMethodInfo(); 49 | 50 | CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); 51 | LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute 52 | .getAttribute(LocalVariableAttribute.tag); 53 | if (attr == null) { 54 | throw new RuntimeException("class:"+clazz.getName() 55 | +", have no LocalVariableTable, please use javac -g:{vars} to compile the source file"); 56 | } 57 | 58 | // for(int i = 0 ; i< attr.length() ; i++){ 59 | // System.out.println(i); 60 | // try { 61 | // System.out.println("===="+attr.nameIndex(i)); 62 | // System.out.println("===="+attr.index(i)); 63 | //// System.out.println("===="+attr.nameIndex(i)); 64 | // System.out.println(clazz.getName()+"================"+i+attr.variableName(i)); 65 | // 66 | // 67 | // } catch (Exception e) { 68 | // // TODO Auto-generated catch block 69 | // e.printStackTrace(); 70 | // } 71 | // } 72 | //addContextVariable by lzw 用于兼容jdk 编译时 LocalVariableTable顺序问题 73 | int startIndex = getStartIndex(attr); 74 | String[] paramNames = new String[cm.getParameterTypes().length]; 75 | int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1; 76 | 77 | for (int i = 0; i < paramNames.length; i++) 78 | paramNames[i] = attr.variableName(startIndex + i + pos); 79 | // paramNames即参数名 80 | for (int i = 0; i < paramNames.length; i++) { 81 | System.out.println(paramNames[i]); 82 | } 83 | 84 | return paramNames; 85 | 86 | } catch (NotFoundException e) { 87 | e.printStackTrace(); 88 | return new String[0]; 89 | } 90 | } 91 | 92 | private int getStartIndex(LocalVariableAttribute attr){ 93 | 94 | // attr.st 95 | 96 | int startIndex = 0; 97 | for(int i = 0 ; i< attr.length() ; i++){ 98 | if("this".equals(attr.variableName(i))){ 99 | startIndex = i; 100 | break; 101 | } 102 | } 103 | return startIndex; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /core/src/test/java/learn/MapTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | package learn; 23 | 24 | import com.google.common.collect.Maps; 25 | import org.junit.Test; 26 | 27 | import java.util.Map; 28 | 29 | /** 30 | * @author Service Platform Architecture Team (spat@58.com) 31 | */ 32 | public class MapTest { 33 | 34 | @Test 35 | public void testToString() { 36 | Map map = Maps.newLinkedHashMap(); 37 | 38 | map.put("a", 1); 39 | map.put("b", "x"); 40 | map.put("c", true); 41 | 42 | System.out.println(map.toString()); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/test/java/learn/MyClassLoader1.java: -------------------------------------------------------------------------------- 1 | package learn; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.Channels; 9 | import java.nio.channels.FileChannel; 10 | import java.nio.channels.WritableByteChannel; 11 | 12 | /** 13 | * @author haojian 14 | * 15 | */ 16 | public class MyClassLoader1 extends ClassLoader { 17 | 18 | public MyClassLoader1(ClassLoader parent) { 19 | super(parent); 20 | } 21 | 22 | public Class findClass1(String name) throws Exception { 23 | byte[] bytes = loadClassBytes(name); 24 | Class theClass = defineClass(null, bytes, 0, bytes.length); 25 | if (theClass == null) 26 | throw new ClassFormatError(); 27 | return theClass; 28 | } 29 | 30 | private byte[] loadClassBytes(String classFile) throws Exception { 31 | // String classFile = getClassFile(); 32 | FileInputStream fis = new FileInputStream(classFile); 33 | FileChannel fileC = fis.getChannel(); 34 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 35 | WritableByteChannel outC = Channels.newChannel(baos); 36 | ByteBuffer buffer = ByteBuffer.allocateDirect(1024); 37 | while (true) { 38 | int i = fileC.read(buffer); 39 | if (i == 0 || i == -1) { 40 | break; 41 | } 42 | buffer.flip(); 43 | outC.write(buffer); 44 | buffer.clear(); 45 | } 46 | fis.close(); 47 | return baos.toByteArray(); 48 | 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /core/src/test/java/learn/PokerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | package learn; 23 | 24 | import junit.framework.Assert; 25 | import org.junit.Test; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import java.util.Random; 30 | 31 | /** 32 | * @author Service Platform Architecture Team (spat@58.com) 33 | */ 34 | public class PokerTest { 35 | Random rdm = new Random(System.currentTimeMillis()); 36 | 37 | @Test 38 | public void test() { 39 | int count = 0; 40 | for(int i = 1; i < 100 * 100 * 100 * 100; i++) { 41 | count += occasion() ? 1 : 0; 42 | if (i % 1000000 == 0) 43 | System.out.println("i:" + i + ", count: " + count + ", " + (count * 1.0)/i); 44 | 45 | } 46 | 47 | System.out.println("i:" + 100 * 100 * 100 + ", count: " + count + ", " + (count * 1.0)/(100 * 100 * 100)); 48 | } 49 | 50 | public boolean occasion() { 51 | List origin = new ArrayList(54); 52 | for(int i = 1; i <= 54; i++) 53 | origin.add(i); 54 | 55 | int[] data = new int[54]; 56 | 57 | for(int i = 53; i >= 1; i--) { 58 | int index = rdm.nextInt(i); 59 | data[i] = origin.remove(index); 60 | Assert.assertTrue(data[i] > 0); 61 | } 62 | 63 | data[0] = origin.remove(0); 64 | Assert.assertTrue(data[0] > 0); 65 | Assert.assertTrue(origin.size() == 0); 66 | 67 | int first = -1; 68 | for(int i = 0; i < 51; i++) { 69 | if (first != -1 && first/17 != i/17) 70 | return false; 71 | 72 | if (data[i] < 3) { 73 | if (first != -1) 74 | return true; 75 | first = i; 76 | } 77 | } 78 | 79 | return false; 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /core/src/test/java/learn/guice/LearnKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package learn.guice; 22 | 23 | import com.bj58.argo.inject.ArgoSystem; 24 | import com.google.inject.*; 25 | import com.google.inject.name.Names; 26 | import org.testng.annotations.Test; 27 | 28 | /** 29 | * @author Service Platform Architecture Team (spat@58.com) 30 | */ 31 | public class LearnKey { 32 | 33 | @ImplementedBy(Action1.class) 34 | public static interface Action { 35 | String process(); 36 | } 37 | 38 | public static class Action1 implements Action { 39 | 40 | @Override 41 | public String process() { 42 | return "action1"; 43 | } 44 | } 45 | 46 | @ArgoSystem 47 | public static class Action2 implements Action { 48 | 49 | private long time = System.nanoTime(); 50 | 51 | @Override 52 | public String process() { 53 | return "action2" + time; 54 | } 55 | } 56 | 57 | @Test 58 | public void test() { 59 | 60 | Injector injector = Guice.createInjector(new ActionModule()); 61 | 62 | Action action1 = injector.getInstance(Action.class); 63 | 64 | System.out.println(action1.process()); 65 | 66 | Action action2 = injector.getInstance(Key.get(Action.class, Names.named("ABC"))); 67 | 68 | System.out.println(action2.process()); 69 | 70 | Action action3 = injector.getInstance(Key.get(Action.class, ArgoSystem.class)); 71 | 72 | System.out.println(action2.process()); 73 | 74 | } 75 | 76 | 77 | public static class ActionModule extends AbstractModule { 78 | 79 | @Override 80 | protected void configure() { 81 | bind(Action.class).annotatedWith(Names.named("ABC")).to(Action2.class); 82 | } 83 | 84 | 85 | 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /plugin/BJ58-SPAT-Plugins_Argo_DOC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/58code/Argo/083e851e1ed4f29a6e228fb1506224cbca6687eb/plugin/BJ58-SPAT-Plugins_Argo_DOC.pdf -------------------------------------------------------------------------------- /plugin/com.bj58.spat.plugins.argo_1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/58code/Argo/083e851e1ed4f29a6e228fb1506224cbca6687eb/plugin/com.bj58.spat.plugins.argo_1.0.0.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.bj58.spat 5 | argo-project 6 | 1.0-SNAPSHOT 7 | pom 8 | 9 | core 10 | samples/hello-world 11 | samples/company 12 | 13 | 14 | 58.com argo 15 | 58.com argo 16 | https://github.com/58code/Argo 17 | 18 | 19 | 58.com 20 | http://www.58.com/ 21 | 22 | 23 | 24 | 25 | The Apache Software License, Version 2.0 26 | http://www.apache.org/licenses/LICENSE-2.0.txt 27 | repo 28 | 29 | 30 | 31 | 32 | 33 | 34 | SPAT 35 | Service Platform Architecture Team 36 | https://github.com/58code 37 | spat@58.com 38 | 39 | 40 | 41 | renjun 42 | renjun 43 | http://weibo.com/duoway 44 | rjun@outlook.com 45 | 46 | 47 | 48 | liuzw 49 | liu zhongwei 50 | liuzw@58.com 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /samples/company/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | com.bj58.spat 6 | company-sample 7 | 1.0.0 8 | 4.0.0 9 | war 10 | 11 | 12 | 13 | com.bj58.spat 14 | argo 15 | 1.0.0 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | provided 22 | 3.0.1 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-war-plugin 34 | 2.3 35 | 36 | false 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-compiler-plugin 45 | 2.5.1 46 | 47 | 1.6 48 | 1.6 49 | UTF-8 50 | 51 | 52 | 53 | 54 | org.apache.tomcat.maven 55 | tomcat7-maven-plugin 56 | 2.0 57 | 58 | / 59 | 80 60 | 61 | 62 | 63 | 64 | 65 | org.mortbay.jetty 66 | jetty-maven-plugin 67 | 68 | 69 | 70 | 9966 71 | foo 72 | 0 73 | 74 | 75 | 80 76 | 60000 77 | 78 | 79 | 80 | / 81 | 82 | 83 | 84 | 85 | org.apache.maven.plugins 86 | maven-compiler-plugin 87 | 2.5.1 88 | 89 | 1.6 90 | 1.6 91 | UTF-8 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /samples/company/src/main/java/com/bj58/argo/GroupConventionBinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.bj58.argo; 22 | 23 | import com.bj58.argo.convention.GroupConventionAnnotation; 24 | 25 | /** 26 | * 27 | * 演示如何自定义组织策略 28 | * 29 | * @author Service Platform Architecture Team (spat@58.com) 30 | */ 31 | @GroupConventionAnnotation( 32 | groupPackagesPrefix = "com.mycompany" 33 | ) 34 | public class GroupConventionBinder { 35 | } 36 | -------------------------------------------------------------------------------- /samples/company/src/main/java/com/mycompany/sample/controllers/HomeController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Beijing 58 Information Technology Co.,Ltd. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | package com.mycompany.sample.controllers; 22 | 23 | import com.bj58.argo.ActionResult; 24 | import com.bj58.argo.BeatContext; 25 | import com.bj58.argo.annotations.Path; 26 | import com.bj58.argo.controller.AbstractController; 27 | 28 | /** 29 | * @author Service Platform Architecture Team (spat@58.com) 30 | */ 31 | @Path("hello") 32 | public class HomeController extends AbstractController{ 33 | 34 | @Path("") 35 | public ActionResult hello() { 36 | return writer().write("Hello world"); 37 | } 38 | 39 | @Path("argo") 40 | public ActionResult helloArgo() { 41 | return writer().write("Hello, argo"); 42 | } 43 | 44 | @Path("{name}") 45 | public ActionResult helloWorld(String name) { 46 | return writer().write("Hello, %s", name); 47 | } 48 | 49 | /** 50 | * 这个是一个比较复杂的例子, 51 | * Path中的路径可以用正则表达式匹配, 52 | * @Path("{phoneNumber:\\d+}")和@Path("{name}")的匹配顺序是 53 | * 如果都匹配,先匹配模板路径长的也就是@Path("{phoneNumber:\\d+}") 54 | * 55 | * @param phoneNumber 56 | * @return 57 | */ 58 | @Path("{phoneNumber:\\d+}") 59 | public ActionResult helloView(int phoneNumber) { 60 | BeatContext beatContext = beat(); 61 | 62 | beatContext 63 | .getModel() 64 | .add("title", "phone") 65 | .add("phoneNumber", phoneNumber); 66 | 67 | return view("hello"); 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /samples/company/src/main/resources/views/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $title 5 | 6 | 7 | 这是一个demo,页面渲染采用velocity。 8 |

call me, $phoneNumber

9 | 10 | -------------------------------------------------------------------------------- /samples/company/src/main/webapp/1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | aaaaa 8 | 9 | -------------------------------------------------------------------------------- /samples/hello-world/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | com.bj58.spat 6 | argo-hello-world 7 | 1.0.0 8 | 4.0.0 9 | war 10 | 11 | 12 | 13 | com.bj58.spat 14 | argo 15 | 1.0.0 16 | 17 | 18 | 19 | javax.servlet 20 | javax.servlet-api 21 | provided 22 | 3.0.1 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.apache.maven.plugins 32 | maven-war-plugin 33 | 2.3 34 | 35 | false 36 | 37 | 38 | 39 | 40 | org.apache.maven.plugins 41 | maven-compiler-plugin 42 | 2.5.1 43 | 44 | 1.6 45 | 1.6 46 | UTF-8 47 | 48 | 49 | 50 | 51 | org.apache.tomcat.maven 52 | tomcat7-maven-plugin 53 | 2.0 54 | 55 | / 56 | 80 57 | 58 | 59 | 60 | 61 | 62 | org.mortbay.jetty 63 | jetty-maven-plugin 64 | 65 | 66 | 67 | 9966 68 | foo 69 | 0 70 | 71 | 72 | 80 73 | 60000 74 | 75 | 76 | 77 | / 78 | 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-compiler-plugin 84 | 2.5.1 85 | 86 | 1.6 87 | 1.6 88 | UTF-8 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/java/com/bj58/argo/controllers/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.bj58.argo.controllers; 2 | 3 | import com.bj58.argo.ActionResult; 4 | import com.bj58.argo.annotations.Path; 5 | import com.bj58.argo.controller.AbstractController; 6 | 7 | public class HelloController extends AbstractController { 8 | 9 | @Path("hello/{name}") 10 | public ActionResult hello(String name) { 11 | 12 | return writer().write("hello %s", name); 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/java/com/bj58/argo/controllers/HomeController.java: -------------------------------------------------------------------------------- 1 | // 包的命名规则受 GroupConvetionAnnotation.groupPackagesPrefix 2 | package com.bj58.argo.controllers; 3 | 4 | import com.bj58.argo.ActionResult; 5 | import com.bj58.argo.BeatContext; 6 | import com.bj58.argo.annotations.POST; 7 | import com.bj58.argo.annotations.Path; 8 | import com.bj58.argo.client.ClientContext; 9 | import com.bj58.argo.client.Upload; 10 | import com.bj58.argo.controller.AbstractController; 11 | import com.google.common.base.Preconditions; 12 | import com.google.common.base.Strings; 13 | 14 | // 类的命名受 GroupConvetionAnnotation.controllerPattern约束 15 | public class HomeController extends AbstractController { 16 | 17 | @Path("") 18 | public ActionResult home() { 19 | // System.out.println(1); 20 | return view("index"); // velocity模板是 /src/main/java/resources/views/index.html 21 | } 22 | 23 | @Path("post.html") 24 | @POST // 只处理post的请求 25 | public ActionResult postForm() { 26 | 27 | BeatContext beat = beat(); 28 | 29 | ClientContext client = beat.getClient(); 30 | 31 | Preconditions.checkState(Strings.isNullOrEmpty(client.form("company"))); 32 | Preconditions.checkState(Strings.isNullOrEmpty(client.form("address"))); 33 | 34 | client.queryString("name"); 35 | 36 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("name"))); 37 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("phone"))); 38 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("submit"))); 39 | 40 | 41 | beat.getModel() 42 | .add("company", client.queryString("company")) 43 | .add("address", client.queryString("address")) 44 | 45 | .add("name", client.form("name")) 46 | .add("phone", client.form("phone")) 47 | .add("submit", client.form("submit")); 48 | 49 | 50 | return view("post"); // resources/views/post.html velocity模板 51 | 52 | } 53 | 54 | /** 55 | * 56 | * 处理文件上传 57 | * 58 | */ 59 | @Path("post-upload.html") 60 | @POST // 只处理post的请求 61 | public ActionResult postUpload() { 62 | 63 | BeatContext beat = beat(); 64 | 65 | ClientContext client = beat.getClient(); 66 | 67 | Preconditions.checkState(Strings.isNullOrEmpty(client.form("company"))); 68 | Preconditions.checkState(Strings.isNullOrEmpty(client.form("address"))); 69 | Preconditions.checkState(Strings.isNullOrEmpty(client.form("file"))); 70 | 71 | client.queryString("name"); 72 | 73 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("name"))); 74 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("phone"))); 75 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("submit"))); 76 | Preconditions.checkState(Strings.isNullOrEmpty(client.queryString("file"))); 77 | 78 | 79 | Upload upload = client.getUpload("file"); 80 | 81 | 82 | beat.getModel() 83 | .add("company", client.queryString("company")) 84 | .add("address", client.queryString("address")) 85 | 86 | .add("name", client.form("name")) 87 | .add("phone", client.form("phone")) 88 | .add("submit", client.form("submit")) 89 | 90 | .add("upload", upload); 91 | 92 | 93 | 94 | return view("post-upload"); // resources/views/post-upload.html velocity模板 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/resources/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Argo sample page 4 | 5 | 6 |

Samples

7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/resources/views/post-upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | form 4 | 5 | 6 |

form post

7 | 8 |

upload file

9 |
    10 |
  • file name: $upload.fileName 注:调用 Upload.getFileName()实现,以下同理
  • 11 |
  • file size: $upload.size
  • 12 |
  • file contentType: $upload.contentType
  • 13 |
14 | 15 |

queryString parameter

16 |
    17 |
  • company: $company
  • 18 |
  • address: $address
  • 19 |
20 |

form parameter

21 |
    22 |
  • name: $name
  • 23 |
  • phone: $phone
  • 24 |
  • submit: $submit
  • 25 |
26 | 27 |

28 | 29 | 处理的Action是 HomeController.postForm 30 | 31 | 32 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/resources/views/post.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | form 4 | 5 | 6 |

form post

7 |

queryString parameter

8 |
    9 |
  • company: $company
  • 10 |
  • address: $address
  • 11 |
12 |

form parameter

13 |
    14 |
  • name: $name
  • 15 |
  • phone: $phone
  • 16 |
  • submit: $submit
  • 17 |
18 | 19 |

20 | 21 | 处理的Action是 HomeController.postForm 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/webapp/1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | bbbbbbbbbbbbbbbbbbb 4 | 5 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/webapp/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 |
    10 |
  • name:
  • 11 |
  • phone:
  • 12 |
13 | 14 | 15 | 16 |
17 | 18 |

19 | 20 | 这是一个表单提交页面
21 | action="post.html?company=58.com&address=beijing"
22 | 我们希望在post.html(对应的Action是HomeController.postForm())中能区分queryString和form的数据。 23 | 24 | 25 | -------------------------------------------------------------------------------- /samples/hello-world/src/main/webapp/upload-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

10 |
    11 |
  • name:
  • 12 |
  • phone:
  • 13 |
  • file:
  • 14 |
15 | 16 | 17 | 18 |
19 | 20 |

21 | 22 | 这是一个表单提交页面
23 | action="post-upload.html?company=58.com&address=beijing"
24 | 我们希望在post-upload.html(对应的Action是HomeController.postUpload())中能区分queryString和form的数据。 25 | 26 | 27 | 28 | 29 | --------------------------------------------------------------------------------