headers, String body, String contentType) {
46 | return client.execute(url, rasDomain, socketTimeout, method, headers, body, contentType);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/common/type/ParameterizedTypeImpl.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.common.type;
2 |
3 | import java.lang.reflect.MalformedParameterizedTypeException;
4 | import java.lang.reflect.ParameterizedType;
5 | import java.lang.reflect.Type;
6 | import java.lang.reflect.TypeVariable;
7 | import java.util.Arrays;
8 |
9 | /**
10 | * Implementing class for ParameterizedType interface.
11 | * 具体请看 {@link sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl}
12 | */
13 | public class ParameterizedTypeImpl implements ParameterizedType {
14 | private final Type[] actualTypeArguments;
15 | private final Class> rawType;
16 | private final Type ownerType;
17 |
18 | private ParameterizedTypeImpl(Class> rawType,
19 | Type[] actualTypeArguments,
20 | Type ownerType) {
21 | this.actualTypeArguments = actualTypeArguments;
22 | this.rawType = rawType;
23 | this.ownerType = (ownerType != null) ? ownerType : rawType.getDeclaringClass();
24 | validateConstructorArguments();
25 | }
26 |
27 | private void validateConstructorArguments() {
28 | TypeVariable>[] formals = rawType.getTypeParameters();
29 | // check correct arity of actual type args
30 | if (formals.length != actualTypeArguments.length) {
31 | throw new MalformedParameterizedTypeException();
32 | }
33 | for (int i = 0; i < actualTypeArguments.length; i++) {
34 | // check actuals against formals' bounds
35 | }
36 | }
37 |
38 | /**
39 | * Static factory. Given a (generic) class, actual type arguments
40 | * and an owner type, creates a parameterized type.
41 | * This class can be instantiated with a raw type that does not
42 | * represent a generic type, provided the list of actual type
43 | * arguments is empty.
44 | * If the ownerType argument is null, the declaring class of the
45 | * raw type is used as the owner type.
46 | * This method throws a MalformedParameterizedTypeException
47 | * under the following circumstances:
48 | * If the number of actual type arguments (i.e., the size of the
49 | * array {@code typeArgs}) does not correspond to the number of
50 | * formal type arguments.
51 | * If any of the actual type arguments is not an instance of the
52 | * bounds on the corresponding formal.
53 | *
54 | * @param rawType the Class representing the generic type declaration being
55 | * instantiated
56 | * @param actualTypeArguments a (possibly empty) array of types
57 | * representing the actual type arguments to the parameterized type
58 | * @param ownerType the enclosing type, if known.
59 | * @return An instance of {@code ParameterizedType}
60 | * @throws MalformedParameterizedTypeException if the instantiation
61 | * is invalid
62 | */
63 | public static ParameterizedTypeImpl make(Class> rawType,
64 | Type[] actualTypeArguments,
65 | Type ownerType) {
66 | return new ParameterizedTypeImpl(rawType, actualTypeArguments,
67 | ownerType);
68 | }
69 |
70 |
71 | /**
72 | * Returns an array of {@code Type} objects representing the actual type
73 | * arguments to this type.
74 | *
75 | *
Note that in some cases, the returned array be empty. This can occur
76 | * if this type represents a non-parameterized type nested within
77 | * a parameterized type.
78 | *
79 | * @return an array of {@code Type} objects representing the actual type
80 | * arguments to this type
81 | * @throws TypeNotPresentException if any of the
82 | * actual type arguments refers to a non-existent type declaration
83 | * @throws MalformedParameterizedTypeException if any of the
84 | * actual type parameters refer to a parameterized type that cannot
85 | * be instantiated for any reason
86 | * @since 1.5
87 | */
88 | @Override
89 | public Type[] getActualTypeArguments() {
90 | return actualTypeArguments.clone();
91 | }
92 |
93 | /**
94 | * Returns the {@code Type} object representing the class or interface
95 | * that declared this type.
96 | *
97 | * @return the {@code Type} object representing the class or interface
98 | * that declared this type
99 | */
100 | @Override
101 | public Class> getRawType() {
102 | return rawType;
103 | }
104 |
105 |
106 | /**
107 | * Returns a {@code Type} object representing the type that this type
108 | * is a member of. For example, if this type is {@code O.I},
109 | * return a representation of {@code O}.
110 | *
111 | * If this type is a top-level type, {@code null} is returned.
112 | *
113 | * @return a {@code Type} object representing the type that
114 | * this type is a member of. If this type is a top-level type,
115 | * {@code null} is returned
116 | * @throws TypeNotPresentException if the owner type
117 | * refers to a non-existent type declaration
118 | * @throws MalformedParameterizedTypeException if the owner type
119 | * refers to a parameterized type that cannot be instantiated
120 | * for any reason
121 | */
122 | @Override
123 | public Type getOwnerType() {
124 | return ownerType;
125 | }
126 |
127 | /**
128 | * From the JavaDoc for java.lang.reflect.ParameterizedType
129 | * "Instances of classes that implement this interface must
130 | * implement an equals() method that equates any two instances
131 | * that share the same generic type declaration and have equal
132 | * type parameters."
133 | */
134 | @Override
135 | public boolean equals(Object o) {
136 | if (o instanceof ParameterizedType) {
137 | // Check that information is equivalent
138 | ParameterizedType that = (ParameterizedType) o;
139 |
140 | if (this == that) {
141 | return true;
142 | }
143 |
144 | Type thatOwner = that.getOwnerType();
145 | Type thatRawType = that.getRawType();
146 |
147 | return
148 | equals(ownerType, thatOwner) &&
149 | equals(rawType, thatRawType) &&
150 | Arrays.equals(actualTypeArguments,
151 | that.getActualTypeArguments());
152 | } else {
153 | return false;
154 | }
155 | }
156 |
157 | @Override
158 | public int hashCode() {
159 | return
160 | Arrays.hashCode(actualTypeArguments) ^
161 | hashCode(ownerType) ^
162 | hashCode(rawType);
163 | }
164 |
165 | boolean equals(Object a, Object b) {
166 | return (a == b) || (a != null && a.equals(b));
167 | }
168 |
169 | int hashCode(Object o) {
170 | return o != null ? o.hashCode() : 0;
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/common/type/TypeReference.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.common.type;
2 |
3 |
4 | import java.lang.reflect.ParameterizedType;
5 | import java.lang.reflect.Type;
6 |
7 | /**
8 | * This generic abstract class is used for obtaining full generics type information
9 | * by sub-classing; it must be converted to {@code com.fasterxml.jackson.core.type.ResolvedType} implementation
10 | * (implemented by JavaType
from "databind" bundle) to be used.
11 | * Class is based on ideas from
12 | * http://gafter.blogspot.com/2006/12/super-type-tokens.html,
14 | * Additional idea (from a suggestion made in comments of the article)
15 | * is to require bogus implementation of Comparable
16 | * (any such generic interface would do, as long as it forces a method
17 | * with generic type to be implemented).
18 | * to ensure that a Type argument is indeed given.
19 | *
20 | * Usage is by sub-classing: here is one way to instantiate reference
21 | * to generic type List<Integer>
:
22 | *
23 | * TypeReference ref = new TypeReference<List<Integer>>() { };
24 | *
25 | * which can be passed to methods that accept TypeReference, or resolved
26 | * using TypeFactory
to obtain {@code com.fasterxml.jackson.core.type.ResolvedType}.
27 | */
28 | public abstract class TypeReference implements Comparable> {
29 | protected final Type _type;
30 |
31 | protected TypeReference() {
32 | Type superClass = getClass().getGenericSuperclass();
33 | if (superClass instanceof Class>) { // sanity check, should never happen
34 | throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
35 | }
36 | /* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect
37 | * it is possible to make it fail?
38 | * But let's deal with specific
39 | * case when we know an actual use case, and thereby suitable
40 | * workarounds for valid case(s) and/or error to throw
41 | * on invalid one(s).
42 | */
43 | _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
44 | }
45 |
46 | public Type getType() {
47 | return _type;
48 | }
49 |
50 | /**
51 | * The only reason we define this method (and require implementation
52 | * of Comparable
) is to prevent constructing a
53 | * reference without type information.
54 | */
55 | @Override
56 | public int compareTo(TypeReference o) {
57 | return 0;
58 | }
59 | // just need an implementation, not a good one... hence ^^^
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/common/util/Utils.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.common.util;
2 |
3 | import com.getui.push.v2.sdk.common.Strings;
4 |
5 | import java.util.Collection;
6 | import java.util.Map;
7 |
8 | public final class Utils {
9 |
10 | public static boolean isEmpty(Map map) {
11 | return map == null || map.size() == 0;
12 | }
13 |
14 | public static boolean isNotEmpty(Map map) {
15 | return map != null && map.size() > 0;
16 | }
17 |
18 | public static boolean isEmpty(Collection collection) {
19 | return collection == null || collection.size() == 0;
20 | }
21 |
22 | public static boolean isNotEmpty(Collection collection) {
23 | return collection != null && collection.size() > 0;
24 | }
25 |
26 | public static boolean isEmpty(CharSequence sequence) {
27 | return Strings.isBlank(sequence);
28 | }
29 |
30 | public static boolean isNotEmpty(CharSequence sequence) {
31 | return Strings.isNotBlank(sequence);
32 | }
33 |
34 | public static boolean isEmpty(Object[] array) {
35 | return array == null || array.length == 0;
36 | }
37 |
38 | public static boolean isNotEmpty(Object[] array) {
39 | return array != null && array.length > 0;
40 | }
41 |
42 | public static boolean isEmpty(byte[] array) {
43 | return array == null || array.length == 0;
44 | }
45 |
46 | public static boolean isNotEmpty(byte[] array) {
47 | return array != null && array.length > 0;
48 | }
49 |
50 |
51 | public static boolean isNumeric(final CharSequence cs) {
52 | if (isEmpty(cs)) {
53 | return false;
54 | }
55 | final int sz = cs.length();
56 | for (int i = 0; i < sz; i++) {
57 | if (!Character.isDigit(cs.charAt(i))) {
58 | return false;
59 | }
60 | }
61 | return true;
62 | }
63 |
64 | static final String v2UrlPrefix = "/v2";
65 |
66 | /**
67 | * 对于v2的接口,一定存在/v2前缀
68 | *
69 | * @param url
70 | * @return
71 | */
72 | public static String v2UrlToHost(String url) {
73 | int v2Index = url.indexOf(v2UrlPrefix);
74 | if (v2Index > 0) {
75 | return url.substring(0, v2Index);
76 | } else {
77 | return url;
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/Configs.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * create by getui on 2020/9/28
8 | *
9 | * @author getui
10 | */
11 | public interface Configs {
12 | int MAX_FAIL_CONTINUOUSLY = 3;
13 |
14 | String HEADER_DOMAIN_HASH_KEY = "domainHash";
15 | String HEADER_OPEN_STABLE_DOMAIN = "openStableDomain";
16 | String SDK_VERSION = "1.0.6.0";
17 | /**
18 | * 预置域名列表
19 | */
20 | List URLS = new ArrayList() {
21 | {
22 | this.add("https://restapi.getui.com/v2/");
23 | this.add("https://cncrestapi.getui.com/v2/");
24 | this.add("https://nzrestapi.getui.com/v2/");
25 | }
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/DefaultJson.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core;
2 |
3 | import com.getui.push.v2.sdk.IJson;
4 | import com.getui.push.v2.sdk.dto.res.statistic.StatisticDTO;
5 | import com.google.gson.*;
6 |
7 | import java.lang.reflect.Type;
8 | import java.text.NumberFormat;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 |
13 | /**
14 | * create by getui on 2020/9/25
15 | *
16 | * @author getui
17 | */
18 | public class DefaultJson implements IJson {
19 | private static final Gson GSON = createGson();
20 |
21 | public static Gson createGson() {
22 | GsonBuilder gsonBuilder = new GsonBuilder();
23 | gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
24 | gsonBuilder.registerTypeAdapter(StatisticDTO.class, new JsonDeserializer() {
25 | @Override
26 | public StatisticDTO deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
27 | StatisticDTO statisticDTO = new StatisticDTO();
28 | JsonObject jo = json.getAsJsonObject();
29 | for (Map.Entry mx : jo.entrySet()) {
30 | String key = mx.getKey();
31 | JsonElement v = mx.getValue();
32 | if (v.isJsonArray()) {
33 | statisticDTO.put(key, context.deserialize(v, List.class));
34 | } else if (v.isJsonPrimitive()) {
35 | Object value = v.getAsString();
36 | try {
37 | Number numValue = NumberFormat.getInstance().parse((String) value);
38 | if (numValue != null && numValue.toString().equals(value)) {
39 | if (numValue instanceof Long && (Long) numValue <= Integer.MAX_VALUE && (Long) numValue >= Integer.MIN_VALUE) {
40 | value = Integer.valueOf((String) value);
41 | } else {
42 | value = numValue;
43 | }
44 | }
45 | } catch (Exception ignored) {
46 | }
47 | statisticDTO.put(key, value);
48 | } else if (v.isJsonObject()) {
49 | statisticDTO.put(key, context.deserialize(v, Map.class));
50 | }
51 | }
52 | return statisticDTO;
53 | }
54 | });
55 | return gsonBuilder.create();
56 | }
57 |
58 |
59 | @Override
60 | public String toJson(Object obj) {
61 | if (obj == null) {
62 | return null;
63 | }
64 | return GSON.toJson(obj);
65 | }
66 |
67 | @Override
68 | public T fromJson(String jsonString, Type type) {
69 | return GSON.fromJson(jsonString, type);
70 | }
71 |
72 | @Override
73 | public T fromJson(String jsonString, Class tClass) {
74 | return GSON.fromJson(jsonString, tClass);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/domain/DomainCheck.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.domain;
2 |
3 | import com.getui.push.v2.sdk.common.util.Utils;
4 |
5 | import java.util.*;
6 |
7 | /**
8 | * create by getui on 2020/7/21
9 | *
10 | * @author getui
11 | */
12 | public class DomainCheck {
13 |
14 | private IDomainCheck check;
15 |
16 | /**
17 | * 检测次数
18 | */
19 | private final int checkSize;
20 |
21 | public DomainCheck(IDomainCheck check) {
22 | this(check, 20);
23 | }
24 |
25 | public DomainCheck(IDomainCheck check, int checkSize) {
26 | this.check = check;
27 | this.checkSize = checkSize;
28 | }
29 |
30 | /**
31 | * 优先级+稳定性 域名排序
32 | */
33 | public List sort(List list) {
34 | Map domainTOGapMap = initGap(list);
35 | List domainList = getALlDomain(list);
36 | Map map = doCheck(domainList, domainTOGapMap);
37 | return doSort(map);
38 | }
39 |
40 | /**
41 | * @param list
42 | * @return
43 | */
44 | private List getALlDomain(List list) {
45 | List domainList = new ArrayList();
46 | for (DomainListBO domainListBO : list) {
47 | if (Utils.isNotEmpty(domainListBO.getDomainList())) {
48 | domainList.addAll(domainListBO.getDomainList());
49 | }
50 | }
51 | return domainList;
52 | }
53 |
54 | private Map doCheck(List domainList, Map domainToGapMap) {
55 | Map detectMap = new HashMap(domainList.size(), 1);
56 | for (int i = 0; i < checkSize; i++) {
57 | //遍历所有的域名进行探测
58 | for (String domain : domainList) {
59 | //遍历所有的域名进行探测
60 | if (detectMap.get(domain) == null) {
61 | detectMap.put(domain, 0);
62 | }
63 | boolean rst = false;
64 | try {
65 | rst = check.check(domain);
66 | } catch (Exception e) {
67 | }
68 | if (rst) {
69 | detectMap.put(domain, detectMap.get(domain) + 1);
70 | }
71 | }
72 | try {
73 | //拉长时间保证稳定性
74 | Thread.sleep(1000);
75 | } catch (InterruptedException e) {
76 | e.printStackTrace();
77 | }
78 | }
79 | //是否所有域名不可用
80 | boolean allBad = true;
81 | //算出 域名-稳定分数
82 | for (Map.Entry entry : detectMap.entrySet()) {
83 | if (entry.getValue() != 0) {
84 | allBad = false;
85 | }
86 | String key = entry.getKey();
87 | int score = (entry.getValue() * 100) / checkSize + domainToGapMap.get(key);
88 | detectMap.put(key, score);
89 | }
90 | if (allBad) {
91 | return Collections.emptyMap();
92 | }
93 | return detectMap;
94 | }
95 |
96 | /**
97 | * 排序
98 | */
99 | private List doSort(Map detectMap) {
100 | List result = new ArrayList();
101 | if (detectMap == null || detectMap.size() == 0) {
102 | return null;
103 | }
104 | String domain = null;
105 | Integer max = 0;
106 | while (detectMap.size() != 0) {
107 | for (Map.Entry entry : detectMap.entrySet()) {
108 | if (entry.getValue() >= max) {
109 | max = entry.getValue();
110 | domain = entry.getKey();
111 | }
112 | }
113 | max = 0;
114 | result.add(domain);
115 | detectMap.remove(domain);
116 | }
117 | return result;
118 | }
119 |
120 | private Map initGap(List list) {
121 | //获取所有的 域名-优先级gap
122 | Map map = new HashMap(list.size(), 1);
123 | int gap = 0;
124 | for (int i = list.size() - 1; i >= 0; i--) {
125 | if (i != list.size() - 1) {
126 | gap += list.get(i).getPriorityGap();
127 | }
128 | for (String t : list.get(i).getDomainList()) {
129 | map.put(t, gap);
130 | }
131 | }
132 | return map;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/domain/DomainListBO.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.domain;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class DomainListBO {
7 | private List domainList;
8 | private Integer priorityGap = 30;
9 |
10 | public List getDomainList() {
11 | return domainList;
12 | }
13 |
14 | public void setDomainList(List domainList) {
15 | this.domainList = domainList;
16 | }
17 |
18 | public Integer getPriorityGap() {
19 | return priorityGap;
20 | }
21 |
22 | public void setPriorityGap(Integer priorityGap) {
23 | this.priorityGap = priorityGap;
24 | }
25 |
26 | public void addDomain(String domainBO) {
27 | if (domainList == null) {
28 | domainList = new ArrayList();
29 | }
30 | domainList.add(domainBO);
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | final StringBuffer sb = new StringBuffer("DomainListBO{");
36 | sb.append("domainList=").append(domainList);
37 | sb.append(", priorityGap=").append(priorityGap);
38 | sb.append('}');
39 | return sb.toString();
40 | }
41 | }
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/domain/IDomainCheck.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.domain;
2 |
3 | /**
4 | * create by getui on 2020/7/21
5 | *
6 | * @author getui
7 | */
8 | public interface IDomainCheck {
9 |
10 | /**
11 | * 域名检测
12 | *
13 | * @param url
14 | * @return true表示成功,false表示失败,成功数越多,表示域名可用性越高
15 | */
16 | boolean check(String url);
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/domain/RasDomainBO.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.domain;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * create by getui on 2020/9/28
7 | *
8 | * @author getui
9 | */
10 | public class RasDomainBO {
11 | private List hostList;
12 | /**
13 | * MD5({@link #hostList})
14 | */
15 | private String domainHash;
16 |
17 | public List getHostList() {
18 | return hostList;
19 | }
20 |
21 | public void setHostList(List hostList) {
22 | this.hostList = hostList;
23 | }
24 |
25 | public String getDomainHash() {
26 | return domainHash;
27 | }
28 |
29 | public void setDomainHash(String domainHash) {
30 | this.domainHash = domainHash;
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | final StringBuffer sb = new StringBuffer("RasDomainBO{");
36 | sb.append("rasHostList=").append(hostList);
37 | sb.append(", domainHash='").append(domainHash).append('\'');
38 | sb.append('}');
39 | return sb.toString();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/factory/GtApiProxyFactory.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.factory;
2 |
3 | import com.getui.push.v2.sdk.anno.param.GtBodyParam;
4 | import com.getui.push.v2.sdk.anno.param.GtPathParam;
5 | import com.getui.push.v2.sdk.anno.param.GtQueryParam;
6 | import com.getui.push.v2.sdk.common.ApiException;
7 | import com.getui.push.v2.sdk.common.Assert;
8 | import com.getui.push.v2.sdk.core.client.DefaultApiClient;
9 | import com.getui.push.v2.sdk.core.registry.DefaultGtApiRegistry;
10 | import com.getui.push.v2.sdk.core.registry.GtApiRegistry;
11 |
12 | import java.lang.annotation.Annotation;
13 | import java.lang.reflect.InvocationHandler;
14 | import java.lang.reflect.Method;
15 | import java.lang.reflect.Proxy;
16 | import java.lang.reflect.Type;
17 | import java.util.ArrayList;
18 | import java.util.Iterator;
19 | import java.util.List;
20 | import java.util.concurrent.ConcurrentHashMap;
21 | import java.util.concurrent.ConcurrentMap;
22 |
23 | /**
24 | * create by getui on 2020/6/4
25 | *
26 | * @author getui
27 | */
28 | public class GtApiProxyFactory {
29 |
30 | /**
31 | * 保证一个{@link DefaultApiClient}对象对应一个{@link GtApiProxyFactory}对象
32 | */
33 | private static ConcurrentMap cache = new ConcurrentHashMap(2);
34 |
35 | DefaultApiClient defaultApiClient;
36 |
37 | /**
38 | * 缓存接口的相关数据,减小解析成本
39 | */
40 | private GtApiRegistry gtApiRegistry;
41 |
42 | public void setGtApiRegistry(GtApiRegistry gtApiRegistry) {
43 | this.gtApiRegistry = gtApiRegistry;
44 | }
45 |
46 | public static GtApiProxyFactory build(DefaultApiClient defaultApiClient) {
47 | GtApiProxyFactory gtApiProxyFactory = cache.get(defaultApiClient);
48 | if (gtApiProxyFactory == null) {
49 | synchronized (cache) {
50 | gtApiProxyFactory = new GtApiProxyFactory(defaultApiClient);
51 | cache.put(defaultApiClient, gtApiProxyFactory);
52 | }
53 | }
54 | return gtApiProxyFactory;
55 | }
56 |
57 | private GtApiProxyFactory(DefaultApiClient defaultApiClient) {
58 | if (defaultApiClient == null) {
59 | throw new ApiException("defaultApiClient cannot be null.", true);
60 | }
61 | this.defaultApiClient = defaultApiClient;
62 | gtApiRegistry = new DefaultGtApiRegistry();
63 | }
64 |
65 | /**
66 | * 创建代理对象
67 | *
68 | * @param apiService
69 | * @param
70 | * @return
71 | */
72 | public T createProxy(Class apiService) {
73 | return (T) Proxy.newProxyInstance(apiService.getClassLoader(), new Class[]{apiService}, new ApiProxyHandler());
74 | }
75 |
76 | class ApiProxyHandler implements InvocationHandler {
77 | @Override
78 | public Object invoke(Object proxy, Method method, Object[] args) {
79 | try {
80 | if (Object.class.equals(method.getDeclaringClass())) {
81 | return method.invoke(this, args);
82 | }
83 | } catch (Throwable t) {
84 | throw new RuntimeException(t);
85 | }
86 | final BaseParam baseParam = gtApiRegistry.get(method);
87 | ApiParam apiParam = new ApiParam(baseParam);
88 | // 解析参数 -> HTTP参数
89 | handleApiParam(method, args, apiParam);
90 | return defaultApiClient.execute(apiParam);
91 | }
92 | }
93 |
94 | /**
95 | * 处理参数, HTTP调用路径参数和body参数
96 | *
97 | * @param method 用于获取方法上的注解
98 | * @param args
99 | * @return notnull
100 | */
101 | private void handleApiParam(Method method, Object[] args, ApiParam apiParam) {
102 | Annotation[][] parameterAnnotations = method.getParameterAnnotations();
103 | for (int i = 0; i < parameterAnnotations.length; i++) {
104 | for (Annotation annotation : parameterAnnotations[i]) {
105 | if (annotation instanceof GtPathParam) {
106 | apiParam.handlePathParam(args[i]);
107 | } else if (annotation instanceof GtQueryParam) {
108 | apiParam.handleQueryParam(args[i], ((GtQueryParam) annotation).name());
109 | } else if (annotation instanceof GtBodyParam) {
110 | apiParam.setBody(args[i]);
111 | }
112 | }
113 | }
114 | }
115 |
116 | /**
117 | * 释放 {@link #cache}中的对象,但是此对象仍然可以使用,直到没有内存引用被回收
118 | */
119 | public void close() {
120 | this.defaultApiClient.close();
121 | cache.remove(this.defaultApiClient);
122 | }
123 |
124 | /**
125 | * HTTP请求的参数
126 | */
127 | public static class ApiParam {
128 | /**
129 | * 基础参数,从方法注解中解析
130 | */
131 | private final BaseParam baseParam;
132 | /**
133 | * 路径参数
134 | */
135 | private String pathParams;
136 | /**
137 | * query参数
138 | */
139 | private List queryParams;
140 | /**
141 | * body参数
142 | */
143 | private Object body;
144 |
145 | public ApiParam(BaseParam baseParam) {
146 | this.baseParam = baseParam;
147 | }
148 |
149 | /**
150 | * 处理路径参数
151 | *
152 | * @param arg
153 | */
154 | public void handlePathParam(Object arg) {
155 | Assert.notNull(arg, "路径参数");
156 | setPathParams(handleArg(arg));
157 | }
158 |
159 | private void addQueryParams(String name, String param) {
160 | if (queryParams == null) {
161 | queryParams = new ArrayList();
162 | }
163 | queryParams.add(name + "=" + param);
164 | }
165 |
166 | public void handleQueryParam(Object arg, String name) {
167 | Assert.notNull(arg, "query参数");
168 | final String param = handleArg(arg);
169 | addQueryParams(name, param);
170 | }
171 |
172 | private String handleArg(Object arg) {
173 | if (arg instanceof Iterable) {
174 | final Iterator iterator = ((Iterable) arg).iterator();
175 | StringBuilder sb = new StringBuilder();
176 | while (iterator.hasNext()) {
177 | sb.append(iterator.next()).append(',');
178 | }
179 | String param = sb.toString();
180 | if (param.endsWith(",")) {
181 | param = param.substring(0, param.length() - 1);
182 | }
183 | return param;
184 | } else if (arg instanceof Number) {
185 | return arg.toString();
186 | } else if (arg instanceof String) {
187 | return (String) arg;
188 | } else {
189 | throw new ApiException("路径参数(加GtPathParam注解的参数)和query参数(加GtQueryParam注解的参数)只能为 Iterable/Number/String的三种类型或其子类型");
190 | }
191 | }
192 |
193 | public String getUri() {
194 | return baseParam.getUri();
195 | }
196 |
197 | public String getMethod() {
198 | return baseParam.getMethod();
199 | }
200 |
201 | public Boolean getNeedToken() {
202 | return baseParam.getNeedToken();
203 | }
204 |
205 | public Type getReturnType() {
206 | return baseParam.getReturnType();
207 | }
208 |
209 | public BaseParam getBaseParam() {
210 | return baseParam;
211 | }
212 |
213 | public String getPathParams() {
214 | return pathParams;
215 | }
216 |
217 | public void setPathParams(String pathParams) {
218 | this.pathParams = pathParams;
219 | }
220 |
221 | public List getQueryParams() {
222 | return queryParams;
223 | }
224 |
225 | public void setQueryParams(List queryParams) {
226 | this.queryParams = queryParams;
227 | }
228 |
229 | public Object getBody() {
230 | return body;
231 | }
232 |
233 | public void setBody(Object body) {
234 | this.body = body;
235 | }
236 |
237 |
238 | @Override
239 | public String toString() {
240 | final StringBuilder sb = new StringBuilder("ApiParam{");
241 | sb.append("baseParam=").append(baseParam);
242 | sb.append(", pathParams='").append(pathParams).append('\'');
243 | sb.append(", queryParams=").append(queryParams);
244 | sb.append(", body=").append(body);
245 | sb.append('}');
246 | return sb.toString();
247 | }
248 | }
249 |
250 | /**
251 | * HTTP请求的参数
252 | */
253 | public static class BaseParam {
254 | /**
255 | * 接口调用相对路径
256 | * eg. /auth
257 | */
258 | private String uri;
259 | /**
260 | * 接口请求方式 GET/POST/PUT/DELETE
261 | */
262 | private String method;
263 |
264 | /**
265 | * 是否需要token
266 | */
267 | private Boolean needToken;
268 | /**
269 | * 返回值类型
270 | */
271 | private Type returnType;
272 |
273 | public String getUri() {
274 | return uri;
275 | }
276 |
277 | public void setUri(String uri) {
278 | this.uri = uri;
279 | }
280 |
281 | public String getMethod() {
282 | return method;
283 | }
284 |
285 | public void setMethod(String method) {
286 | this.method = method;
287 | }
288 |
289 | public Boolean getNeedToken() {
290 | return needToken;
291 | }
292 |
293 | public void setNeedToken(Boolean needToken) {
294 | this.needToken = needToken;
295 | }
296 |
297 | public Type getReturnType() {
298 | return returnType;
299 | }
300 |
301 | public void setReturnType(Type returnType) {
302 | this.returnType = returnType;
303 | }
304 |
305 | @Override
306 | public String toString() {
307 | return "BaseParam{" +
308 | "uri='" + uri + '\'' +
309 | ", method='" + method + '\'' +
310 | ", needToken=" + needToken +
311 | ", returnType=" + returnType +
312 | '}';
313 | }
314 | }
315 |
316 | }
317 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/handler/GtInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.handler;
2 |
3 | import com.getui.push.v2.sdk.common.ApiException;
4 | import com.getui.push.v2.sdk.core.factory.GtApiProxyFactory;
5 |
6 | import java.util.Map;
7 |
8 | /**
9 | * create by getui on 2020/9/28
10 | *
11 | * @author getui
12 | */
13 | public interface GtInterceptor {
14 | /**
15 | * http请求前调用
16 | *
17 | * @param apiParam 请求参数
18 | * @param header 请求header
19 | * @param body 请求body
20 | */
21 | void pre(GtApiProxyFactory.ApiParam apiParam, Map header, String body);
22 |
23 | /**
24 | * http请求成功后调用此方法
25 | *
26 | * @param apiParam 请求参数
27 | * @param header 请求header
28 | * @param body 请求body
29 | * @param result 返回值
30 | */
31 | void post(GtApiProxyFactory.ApiParam apiParam, Map header, String body, String result);
32 |
33 | /**
34 | * 报错时调用此方法
35 | *
36 | * @param host 当前使用的host
37 | * @param apiParam 请求参数
38 | * @param header 请求header
39 | * @param body 请求body
40 | * @param e 异常信息
41 | */
42 | void handleException(String host, GtApiProxyFactory.ApiParam apiParam, Map header, String body, ApiException e);
43 |
44 | /**
45 | * http请求后调用,不管成功或者失败都会调用
46 | *
47 | * @param host 当前使用的host
48 | * @param apiParam 请求参数
49 | * @param header 请求header
50 | * @param body 请求body
51 | * @param result 返回值
52 | */
53 | void afterCompletion(String host, GtApiProxyFactory.ApiParam apiParam, Map header, String body, String result);
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/handler/IHandler.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.handler;
2 |
3 | /**
4 | * create by getui on 2020/6/15
5 | *
6 | * @author getui
7 | */
8 | public interface IHandler {
9 |
10 | /**
11 | * 处理器接口
12 | *
13 | * @param t
14 | * @return
15 | */
16 | T handle(T t);
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/getui/push/v2/sdk/core/handler/header/IHeaderHandler.java:
--------------------------------------------------------------------------------
1 | package com.getui.push.v2.sdk.core.handler.header;
2 |
3 | import com.getui.push.v2.sdk.core.handler.IHandler;
4 |
5 | import java.util.Map;
6 |
7 | /**
8 | * 处理header参数的handler
9 | * create by getui on 2020/6/15
10 | *
11 | * @author getui
12 | */
13 | public interface IHeaderHandler extends IHandler