{@link HuaweiApp#initializeApp(HuaweiOption)} initializes the app instance.
39 | */
40 | public class HuaweiApp {
41 | private static final Logger logger = LoggerFactory.getLogger(HuaweiApp.class);
42 |
43 | private String appId;
44 | private HuaweiOption option;
45 |
46 | /** Global lock */
47 | private static final Object appsLock = new Object();
48 |
49 | /** Store a map of A no-op if delete was called before.
155 | */
156 | public void delete() {
157 | synchronized (lock) {
158 | boolean valueChanged = deleted.compareAndSet(false /* expected */, true);
159 | if (!valueChanged) {
160 | return;
161 | }
162 |
163 | try {
164 | this.getOption().getHttpClient().close();
165 | this.getOption().getCredential().getHttpClient().close();
166 | } catch (IOException e) {
167 | logger.debug("Fail to close httpClient");
168 | }
169 |
170 | for (HuaweiService service : services.values()) {
171 | service.destroy();
172 | }
173 | services.clear();
174 | tokenRefresher.stop();
175 |
176 | threadManager.releaseHuaweiExecutors(this, executors);
177 | if (scheduledExecutor != null) {
178 | scheduledExecutor.shutdown();
179 | scheduledExecutor = null;
180 | }
181 | }
182 |
183 | synchronized (appsLock) {
184 | instances.remove(this.getAppId());
185 | }
186 | }
187 |
188 | /**
189 | * Check the app is not deleted, whcic is the premisi of some methods
190 | */
191 | private void checkNotDeleted() {
192 | String errorMessage = MessageFormat.format("HuaweiApp with id {0} was deleted", getAppId());
193 | ValidatorUtils.checkState(!deleted.get(), errorMessage);
194 | }
195 |
196 | /**
197 | * Singleton mode, ensure the scheduleExecutor is singleton
198 | */
199 | private ScheduledExecutorService singleScheduledExecutorService() {
200 | if (scheduledExecutor == null) {
201 | synchronized (lock) {
202 | checkNotDeleted();
203 | if (scheduledExecutor == null) {
204 | scheduledExecutor = new HuaweiScheduledExecutor(getThreadFactory(), "huawei-scheduled-worker");
205 | }
206 | }
207 | }
208 | return scheduledExecutor;
209 | }
210 |
211 | public ThreadFactory getThreadFactory() {
212 | return threadManager.getThreadFactory();
213 | }
214 |
215 | private ScheduledExecutorService getScheduledExecutorService() {
216 | return singleScheduledExecutorService();
217 | }
218 |
219 | ScheduledFuture> schedule(Runnable runnable, long initialDelay, long period) {
220 | return getScheduledExecutorService().scheduleWithFixedDelay(runnable, initialDelay, period, TimeUnit.MILLISECONDS);
221 | }
222 |
223 | /**
224 | * Add service to the app, such as HuaweiMessaging, other services can be added if needed
225 | */
226 | void addService(HuaweiService service) {
227 | synchronized (lock) {
228 | checkNotDeleted();
229 | ValidatorUtils.checkArgument(!services.containsKey(service.getId()), "service already exists");
230 | services.put(service.getId(), service);
231 | }
232 | }
233 |
234 | HuaweiService getService(String id) {
235 | synchronized (lock) {
236 | return services.get(id);
237 | }
238 | }
239 |
240 | /**
241 | * Start the scheduled task for refreshing token automatically
242 | */
243 | public void startTokenRefresher() {
244 | synchronized (lock) {
245 | checkNotDeleted();
246 | tokenRefresher.start();
247 | }
248 | }
249 |
250 | /** It is just for test */
251 | public static void clearInstancesForTest() {
252 | synchronized (appsLock) {
253 | //copy before delete
254 | for (HuaweiApp app : ImmutableList.copyOf(instances.values())) {
255 | app.delete();
256 | }
257 | instances.clear();
258 | }
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/messaging/HuaweiCredential.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.messaging;
17 |
18 | import com.alibaba.fastjson.JSONObject;
19 |
20 | import org.apache.http.client.methods.CloseableHttpResponse;
21 | import org.apache.http.client.methods.HttpPost;
22 | import org.apache.http.entity.StringEntity;
23 | import org.apache.http.impl.client.CloseableHttpClient;
24 | import org.apache.http.impl.client.HttpClients;
25 | import org.apache.http.util.EntityUtils;
26 | import org.slf4j.Logger;
27 | import org.slf4j.LoggerFactory;
28 |
29 | import java.io.IOException;
30 | import java.text.MessageFormat;
31 | import java.util.ResourceBundle;
32 | import java.util.concurrent.locks.Lock;
33 | import java.util.concurrent.locks.ReentrantLock;
34 |
35 | /**
36 | * Accept the appId and appSecret given by the user and build the credential
37 | * Every app has a credential which is for certification
38 | */
39 | public class HuaweiCredential {
40 | private static final Logger logger = LoggerFactory.getLogger(HuaweiCredential.class);
41 |
42 | private final String PUSH_AT_URL = ResourceBundle.getBundle("url").getString("token_server");
43 |
44 | private String appId;
45 | private String appSecret;
46 |
47 | private String accessToken;
48 | private long expireIn;
49 | private Lock lock;
50 | private CloseableHttpClient httpClient;
51 |
52 | private HuaweiCredential(Builder builder) {
53 | this.lock = new ReentrantLock();
54 | this.appId = builder.appId;
55 | this.appSecret = builder.appSecret;
56 | if (builder.httpClient == null) {
57 | httpClient = HttpClients.createDefault();
58 | } else {
59 | this.httpClient = builder.httpClient;
60 | }
61 | }
62 |
63 | /**
64 | * Refresh accessToken via HCM manually.
65 | */
66 | public final void refreshToken() {
67 | try {
68 | executeRefresh();
69 | } catch (IOException e) {
70 | logger.debug("Fail to refresh token!", e);
71 | }
72 | }
73 |
74 | private void executeRefresh() throws IOException {
75 | String requestBody = createRequestBody(appId, appSecret);
76 |
77 | HttpPost httpPost = new HttpPost(PUSH_AT_URL);
78 | StringEntity entity = new StringEntity(requestBody);
79 | httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
80 | httpPost.setEntity(entity);
81 | CloseableHttpResponse response = httpClient.execute(httpPost);
82 | String jsonStr = EntityUtils.toString(response.getEntity());
83 | int statusCode = response.getStatusLine().getStatusCode();
84 | if (statusCode == 200) {
85 | JSONObject jsonObject = JSONObject.parseObject(jsonStr);
86 | this.accessToken = jsonObject.getString("access_token");
87 | this.expireIn = jsonObject.getLong("expires_in") * 1000L;
88 | } else {
89 | logger.debug("Fail to refresh token!");
90 | }
91 | }
92 |
93 | private String createRequestBody(String appId, String appSecret) {
94 | return MessageFormat.format("grant_type=client_credentials&client_secret={0}&client_id={1}", appSecret, appId);
95 | }
96 |
97 | /**
98 | * getter
99 | */
100 | public final String getAccessToken() {
101 | this.lock.lock();
102 |
103 | String tmp;
104 | try {
105 | tmp = this.accessToken;
106 | } finally {
107 | this.lock.unlock();
108 | }
109 |
110 | return tmp;
111 | }
112 |
113 | public final long getExpireIn() {
114 | this.lock.lock();
115 |
116 | long tmp;
117 | try {
118 | tmp = this.expireIn;
119 | } finally {
120 | this.lock.unlock();
121 | }
122 |
123 | return tmp;
124 | }
125 |
126 | protected CloseableHttpClient getHttpClient() {
127 | return httpClient;
128 | }
129 |
130 | public String getAppId() {
131 | return appId;
132 | }
133 |
134 | /**
135 | * Builder for constructing {@link HuaweiCredential}.
136 | */
137 | public static Builder builder() {
138 | return new Builder();
139 | }
140 |
141 | public static class Builder {
142 | private String appId;
143 | private String appSecret;
144 |
145 | private CloseableHttpClient httpClient;
146 |
147 | private Builder() {
148 | }
149 |
150 | public Builder setAppId(String appId) {
151 | this.appId = appId;
152 | return this;
153 | }
154 |
155 | public Builder setAppSecret(String appSecret) {
156 | this.appSecret = appSecret;
157 | return this;
158 | }
159 |
160 | public Builder setHttpClient(CloseableHttpClient httpClient) {
161 | this.httpClient = httpClient;
162 | return this;
163 | }
164 |
165 | public HuaweiCredential build() {
166 | return new HuaweiCredential(this);
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/messaging/HuaweiMessageClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.messaging;
17 |
18 | import com.huawei.push.exception.HuaweiMesssagingException;
19 | import com.huawei.push.message.Message;
20 | import com.huawei.push.message.TopicMessage;
21 | import com.huawei.push.reponse.SendResponse;
22 |
23 | /**
24 | * sending messages interface
25 | */
26 | public interface HuaweiMessageClient {
27 |
28 | /**
29 | * Sends the given message with HCM.
30 | *
31 | * @param message message {@link Message}
32 | * @param validateOnly A boolean indicating whether to send message for test. or not.
33 | * @return {@link SendResponse}.
34 | * @throws HuaweiMesssagingException
35 | */
36 | SendResponse send(Message message, boolean validateOnly, String accessToken) throws HuaweiMesssagingException;
37 |
38 | SendResponse send(TopicMessage message, String operation, String accessToken) throws HuaweiMesssagingException;
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/messaging/HuaweiMessageClientImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.messaging;
17 |
18 | import com.alibaba.fastjson.JSON;
19 | import com.alibaba.fastjson.JSONArray;
20 | import com.alibaba.fastjson.JSONObject;
21 | import com.huawei.push.exception.HuaweiMesssagingException;
22 | import com.huawei.push.message.Message;
23 | import com.huawei.push.message.TopicMessage;
24 | import com.huawei.push.model.TopicOperation;
25 | import com.huawei.push.reponse.SendResponse;
26 | import com.huawei.push.reponse.TopicListResponse;
27 | import com.huawei.push.reponse.TopicSendResponse;
28 | import com.huawei.push.util.ValidatorUtils;
29 | import org.apache.commons.lang3.StringUtils;
30 | import org.apache.http.client.HttpResponseException;
31 | import org.apache.http.client.methods.CloseableHttpResponse;
32 | import org.apache.http.client.methods.HttpPost;
33 | import org.apache.http.entity.StringEntity;
34 | import org.apache.http.impl.client.CloseableHttpClient;
35 | import org.apache.http.util.EntityUtils;
36 |
37 | import java.io.IOException;
38 | import java.text.MessageFormat;
39 | import java.util.HashMap;
40 | import java.util.Map;
41 | import java.util.ResourceBundle;
42 |
43 | public class HuaweiMessageClientImpl implements HuaweiMessageClient {
44 | private static final String PUSH_URL = ResourceBundle.getBundle("url").getString("push_open_url");
45 |
46 | private final String HcmPushUrl;
47 | private String hcmTopicUrl;
48 | private String hcmGroupUrl;
49 | private String hcmTokenUrl;
50 | private final CloseableHttpClient httpClient;
51 |
52 | private HuaweiMessageClientImpl(Builder builder) {
53 | this.HcmPushUrl = MessageFormat.format(PUSH_URL + "/v1/{0}/messages:send", builder.appId);
54 | this.hcmTopicUrl = MessageFormat.format(PUSH_URL + "/v1/{0}/topic:{1}", builder.appId);
55 |
56 | ValidatorUtils.checkArgument(builder.httpClient != null, "requestFactory must not be null");
57 | this.httpClient = builder.httpClient;
58 | }
59 |
60 | /**
61 | * getter
62 | */
63 | public String getHcmSendUrl() {
64 | return HcmPushUrl;
65 | }
66 |
67 | public CloseableHttpClient getHttpClient() {
68 | return httpClient;
69 | }
70 |
71 | @Override
72 | public SendResponse send(Message message, boolean validateOnly, String accessToken) throws HuaweiMesssagingException {
73 | try {
74 | return sendRequest(message, validateOnly, accessToken);
75 | } catch (IOException e) {
76 | throw new HuaweiMesssagingException(HuaweiMessaging.INTERNAL_ERROR, "Error while calling HCM backend service", e);
77 | }
78 | }
79 |
80 | @Override
81 | public SendResponse send(TopicMessage message, String operation, String accessToken) throws HuaweiMesssagingException {
82 | try {
83 | return sendRequest(message, operation, accessToken);
84 | } catch (IOException e) {
85 | throw new HuaweiMesssagingException(HuaweiMessaging.INTERNAL_ERROR, "Error while calling HCM backend service", e);
86 | }
87 | }
88 |
89 | private SendResponse sendRequest(TopicMessage message, String operation, String accessToken) throws IOException, HuaweiMesssagingException {
90 | this.hcmTopicUrl = MessageFormat.format(hcmTopicUrl, "", operation);
91 | HttpPost httpPost = new HttpPost(this.hcmTopicUrl);
92 | StringEntity entity = new StringEntity(JSON.toJSONString(message), "UTF-8");
93 | httpPost.setHeader("Authorization", "Bearer " + accessToken);
94 | httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
95 | httpPost.setEntity(entity);
96 | CloseableHttpResponse response = httpClient.execute(httpPost);
97 | String rpsContent = EntityUtils.toString(response.getEntity());
98 | int statusCode = response.getStatusLine().getStatusCode();
99 | if (statusCode == 200) {
100 | JSONObject jsonObject = JSONObject.parseObject(rpsContent);
101 | String code = jsonObject.getString("code");
102 | String msg = jsonObject.getString("msg");
103 | String requestId = jsonObject.getString("requestId");
104 | if (StringUtils.equals(code, "80000000")) {
105 | SendResponse sendResponse;
106 | if (StringUtils.equals(operation, TopicOperation.LIST.getValue())) {
107 | JSONArray topics = jsonObject.getJSONArray("topics");
108 | sendResponse = TopicListResponse.fromCode(code, msg, requestId, topics);
109 | } else {
110 | Integer failureCount = jsonObject.getInteger("failureCount");
111 | Integer successCount = jsonObject.getInteger("successCount");
112 | JSONArray errors = jsonObject.getJSONArray("errors");
113 | sendResponse = TopicSendResponse.fromCode(code, msg, requestId, failureCount, successCount, errors);
114 | }
115 | return sendResponse;
116 | } else {
117 | String errorMsg = MessageFormat.format("error code : {0}, error message : {1}", String.valueOf(code), msg);
118 | throw new HuaweiMesssagingException(HuaweiMessaging.KNOWN_ERROR, errorMsg);
119 | }
120 | }
121 | HttpResponseException exception = new HttpResponseException(statusCode, rpsContent);
122 | throw createExceptionFromResponse(exception);
123 | }
124 |
125 | /**
126 | * send request
127 | *
128 | * @param message message {@link Message}
129 | * @param validateOnly A boolean indicating whether to send message for test or not.
130 | * @param accessToken A String for oauth
131 | * @return {@link SendResponse}
132 | * @throws IOException If a error occurs when sending request
133 | */
134 | private SendResponse sendRequest(Message message, boolean validateOnly, String accessToken) throws IOException, HuaweiMesssagingException {
135 | Map You can get a instance of {@link com.huawei.push.messaging.HuaweiMessaging}
34 | * by a instance of {@link com.huawei.push.messaging.HuaweiApp}, and then use it to send a message
35 | */
36 | public class HuaweiMessaging {
37 | private static final Logger logger = LoggerFactory.getLogger(HuaweiMessaging.class);
38 |
39 | static final String INTERNAL_ERROR = "internal error";
40 |
41 | static final String UNKNOWN_ERROR = "unknown error";
42 |
43 | static final String KNOWN_ERROR = "known error";
44 |
45 | private final HuaweiApp app;
46 | private final Supplier extends HuaweiMessageClient> messagingClient;
47 |
48 | private HuaweiMessaging(Builder builder) {
49 | this.app = builder.app;
50 | this.messagingClient = Suppliers.memoize(builder.messagingClient);
51 | }
52 |
53 | /**
54 | * Gets the {@link HuaweiMessaging} instance for the specified {@link HuaweiApp}.
55 | *
56 | * @return The {@link HuaweiMessaging} instance for the specified {@link HuaweiApp}.
57 | */
58 | public static synchronized HuaweiMessaging getInstance(HuaweiApp app) {
59 | HuaweiMessagingService service = ImplHuaweiTrampolines.getService(app, SERVICE_ID, HuaweiMessagingService.class);
60 | if (service == null) {
61 | service = ImplHuaweiTrampolines.addService(app, new HuaweiMessagingService(app));
62 | }
63 | return service.getInstance();
64 | }
65 |
66 | private static HuaweiMessaging fromApp(final HuaweiApp app) {
67 | return HuaweiMessaging.builder()
68 | .setApp(app)
69 | .setMessagingClient(() -> HuaweiMessageClientImpl.fromApp(app))
70 | .build();
71 | }
72 |
73 | HuaweiMessageClient getMessagingClient() {
74 | return messagingClient.get();
75 | }
76 |
77 | /**
78 | * Sends the given {@link Message} via HCM.
79 | *
80 | * @param message A non-null {@link Message} to be sent.
81 | * @return {@link SendResponse}.
82 | * @throws HuaweiMesssagingException If an error occurs while handing the message off to HCM for
83 | * delivery.
84 | */
85 | public SendResponse sendMessage(Message message) throws HuaweiMesssagingException {
86 | return sendMessage(message, false);
87 | }
88 |
89 | /**
90 | * @param topicMessage topicmessage
91 | * @return topic subscribe response
92 | * @throws HuaweiMesssagingException
93 | */
94 | public SendResponse subscribeTopic(TopicMessage topicMessage) throws HuaweiMesssagingException {
95 | final HuaweiMessageClient messagingClient = getMessagingClient();
96 | return messagingClient.send(topicMessage, TopicOperation.SUBSCRIBE.getValue(), ImplHuaweiTrampolines.getAccessToken(app));
97 | }
98 |
99 | /**
100 | * @param topicMessage topic Message
101 | * @return topic unsubscribe response
102 | * @throws HuaweiMesssagingException
103 | */
104 | public SendResponse unsubscribeTopic(TopicMessage topicMessage) throws HuaweiMesssagingException {
105 | final HuaweiMessageClient messagingClient = getMessagingClient();
106 | return messagingClient.send(topicMessage, TopicOperation.UNSUBSCRIBE.getValue(), ImplHuaweiTrampolines.getAccessToken(app));
107 | }
108 |
109 | /**
110 | * @param topicMessage topic Message
111 | * @return topic list
112 | * @throws HuaweiMesssagingException
113 | */
114 | public SendResponse listTopic(TopicMessage topicMessage) throws HuaweiMesssagingException {
115 | final HuaweiMessageClient messagingClient = getMessagingClient();
116 | return messagingClient.send(topicMessage, TopicOperation.LIST.getValue(), ImplHuaweiTrampolines.getAccessToken(app));
117 | }
118 |
119 |
120 | /**
121 | * Sends message {@link Message}
122 | *
123 | * If the {@code validateOnly} option is set to true, the message will not be actually sent. Instead
124 | * HCM performs all the necessary validations, and emulates the send operation.
125 | *
126 | * @param message message {@link Message} to be sent.
127 | * @param validateOnly a boolean indicating whether to send message for test or not.
128 | * @return {@link SendResponse}.
129 | * @throws HuaweiMesssagingException exception.
130 | */
131 | public SendResponse sendMessage(Message message, boolean validateOnly) throws HuaweiMesssagingException {
132 | ValidatorUtils.checkArgument(message != null, "message must not be null");
133 | final HuaweiMessageClient messagingClient = getMessagingClient();
134 | return messagingClient.send(message, validateOnly, ImplHuaweiTrampolines.getAccessToken(app));
135 | }
136 |
137 | /**
138 | * HuaweiMessagingService
139 | */
140 | private static final String SERVICE_ID = HuaweiMessaging.class.getName();
141 |
142 | private static class HuaweiMessagingService extends HuaweiService If long-lived threads cannot be supported in the current runtime, this method may
67 | * throw a {@code RuntimeException}.
68 | *
69 | * @return A non-null This class is thread safe. It will handle only one token change event at a time. It also
33 | * cancels any pending token refresh events, before scheduling a new one.
34 | */
35 | public class TokenRefresher {
36 | private static final Logger logger = LoggerFactory.getLogger(TokenRefresher.class);
37 |
38 | private HuaweiApp app;
39 | private HuaweiCredential credential;
40 |
41 | private Future future;
42 |
43 | public TokenRefresher(HuaweiApp app) {
44 | ValidatorUtils.checkArgument(app != null, "app must not be null");
45 | this.app = app;
46 | this.credential = app.getOption().getCredential();
47 | }
48 |
49 | protected void scheduleNext(Runnable task, long initialDelay, long period) {
50 | logger.debug("Scheduling next token refresh in {} milliseconds", period);
51 | try {
52 | future = app.schedule(task, initialDelay, period);
53 | } catch (UnsupportedOperationException e) {
54 | logger.debug("Failed to schedule token refresh event", e);
55 | }
56 | }
57 |
58 | /**
59 | * Schedule a forced token refresh to be executed after a specified period.
60 | *
61 | * @param period in milliseconds, after which the token should be forcibly refreshed.
62 | */
63 | public void scheduleRefresh(final long period) {
64 | cancelPrevious();
65 | scheduleNext(() -> credential.refreshToken(), period, period);
66 | }
67 |
68 | private void cancelPrevious() {
69 | if (future != null) {
70 | future.cancel(true);
71 | }
72 | }
73 |
74 | /**
75 | * Starts the TokenRefresher if not already started. Starts refreshing when token is expired. If no active
76 | * token is present, or if the available token is expired soon, this will also refresh immediately.
77 | */
78 | final synchronized void start() {
79 | logger.debug("Starting the proactive token refresher");
80 | String accessToken = credential.getAccessToken();
81 | long refreshDelay;
82 | if (accessToken == null || StringUtils.isEmpty(accessToken)) {
83 | credential.refreshToken();
84 | }
85 |
86 | refreshDelay = credential.getExpireIn();
87 |
88 | scheduleRefresh(refreshDelay);
89 | }
90 |
91 | final synchronized void stop() {
92 | cancelPrevious();
93 | logger.debug("Stopped the proactive token refresher");
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/model/Importance.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.model;
17 |
18 | public enum Importance {
19 | /**
20 | * LOW
21 | */
22 | LOW("LOW"),
23 |
24 | /**
25 | * NORMAL
26 | */
27 | NORMAL("NORMAL"),
28 |
29 | /**
30 | * HIGH
31 | */
32 | HIGH("HIGH");
33 |
34 | private String value;
35 |
36 | private Importance(String value) {
37 | this.value = value;
38 | }
39 |
40 | /**
41 | * Gets value *
42 | *
43 | * @return the value
44 | */
45 | public String getValue() {
46 | return value;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/model/TopicOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.model;
17 |
18 | public enum TopicOperation {
19 | SUBSCRIBE("subscribe"),
20 | UNSUBSCRIBE("unsubscribe"),
21 | LIST("list");
22 |
23 | private String value;
24 |
25 | private TopicOperation(String value) {
26 | this.value = value;
27 | }
28 |
29 | /**
30 | * Gets value *
31 | *
32 | * @return the value
33 | */
34 | public String getValue() {
35 | return value;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/model/Urgency.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.model;
17 |
18 | public enum Urgency {
19 | HIGH("HIGH"),
20 | NORMAL("NORMAL");
21 |
22 | private String value;
23 |
24 | private Urgency(String value) {
25 | this.value = value;
26 | }
27 |
28 | /**
29 | * Gets value *
30 | *
31 | * @return the value
32 | */
33 | public String getValue() {
34 | return value;
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/model/Visibility.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.model;
17 |
18 | public enum Visibility {
19 | VISIBILITY_UNSPECIFIED("VISIBILITY_UNSPECIFIED"),
20 | PRIVATE("PRIVATE"),
21 | PUBLIC("PUBLIC"),
22 | SECRET("SECRET");
23 |
24 | private String value;
25 |
26 | private Visibility(String value) {
27 | this.value = value;
28 | }
29 |
30 | /**
31 | * Gets value *
32 | *
33 | * @return the value
34 | */
35 | public String getValue() {
36 | return value;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/reponse/SendResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.reponse;
17 |
18 | /**
19 | * A class of reponse which exposed to developer
20 | */
21 | public class SendResponse {
22 | private final String code;
23 | private final String msg;
24 | private final String requestId;
25 |
26 |
27 | protected SendResponse(String coede, String msg, String requestId) {
28 | this.code = coede;
29 | this.msg = msg;
30 | this.requestId = requestId;
31 | }
32 |
33 | public String getCode() {
34 | return code;
35 | }
36 |
37 | public String getMsg() {
38 | return msg;
39 | }
40 |
41 | public String getRequestId() {
42 | return requestId;
43 | }
44 |
45 | public static SendResponse fromCode(String coede, String msg, String requestId) {
46 | return new SendResponse(coede, msg, requestId);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/reponse/TopicListResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.reponse;
17 |
18 | import com.alibaba.fastjson.JSONArray;
19 |
20 | public class TopicListResponse extends SendResponse {
21 | private final JSONArray topics;
22 |
23 | public JSONArray getTopics() {
24 | return topics;
25 | }
26 |
27 | private TopicListResponse(String code, String msg, String requestId, JSONArray topics) {
28 | super(code, msg, requestId);
29 | this.topics = topics;
30 | }
31 |
32 | public static TopicListResponse fromCode(String code, String msg, String requestId, JSONArray topics) {
33 | return new TopicListResponse(code, msg, requestId, topics);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/reponse/TopicSendResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.reponse;
17 |
18 | import com.alibaba.fastjson.JSONArray;
19 |
20 | public final class TopicSendResponse extends SendResponse {
21 | private final Integer failureCount;
22 | private final Integer successCount;
23 | private final JSONArray errors;
24 |
25 | public Integer getFailureCount() {
26 | return failureCount;
27 | }
28 |
29 | public Integer getSuccessCount() {
30 | return successCount;
31 | }
32 |
33 | public JSONArray getErrors() {
34 | return errors;
35 | }
36 |
37 | private TopicSendResponse(String code, String msg, String requestId, Integer failureCount, Integer successCount, JSONArray errors) {
38 | super(code,msg,requestId);
39 | this.failureCount = failureCount;
40 | this.successCount = successCount;
41 | this.errors = errors;
42 | }
43 |
44 | public static TopicSendResponse fromCode(String code, String msg, String requestId,Integer failureCount,Integer successCount,JSONArray errors ) {
45 | return new TopicSendResponse(code, msg, requestId,failureCount,successCount,errors);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/util/CollectionUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.util;
17 |
18 | import java.util.Collection;
19 | import java.util.Map;
20 |
21 | /**
22 | * A tool for processing collections
23 | */
24 | public class CollectionUtils {
25 | public CollectionUtils() {
26 | }
27 |
28 | public static boolean isEmpty(Collection> collection) {
29 | return collection == null || collection.isEmpty();
30 | }
31 |
32 | public static boolean isEmpty(Map, ?> map) {
33 | return map == null || map.isEmpty();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/util/IgnoreSSLUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.util;
17 |
18 | import org.apache.http.config.Registry;
19 | import org.apache.http.config.RegistryBuilder;
20 | import org.apache.http.conn.socket.ConnectionSocketFactory;
21 | import org.apache.http.conn.socket.PlainConnectionSocketFactory;
22 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
23 | import org.apache.http.impl.client.CloseableHttpClient;
24 | import org.apache.http.impl.client.HttpClients;
25 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
26 |
27 | import javax.net.ssl.SSLContext;
28 | import javax.net.ssl.TrustManager;
29 | import javax.net.ssl.X509TrustManager;
30 | import java.security.KeyManagementException;
31 | import java.security.NoSuchAlgorithmException;
32 | import java.security.cert.CertificateException;
33 |
34 | /**
35 | * A tool for ignoring ssl when creating httpclient
36 | */
37 | public class IgnoreSSLUtils {
38 | private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
39 | SSLContext sc = SSLContext.getInstance("TLSv1.2");
40 |
41 | X509TrustManager trustManager = new X509TrustManager() {
42 | @Override
43 | public void checkClientTrusted(
44 | java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
45 | String paramString) throws CertificateException {
46 | }
47 |
48 | @Override
49 | public void checkServerTrusted(
50 | java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
51 | String paramString) throws CertificateException {
52 | }
53 |
54 | @Override
55 | public java.security.cert.X509Certificate[] getAcceptedIssuers() {
56 | return null;
57 | }
58 | };
59 |
60 | sc.init(null, new TrustManager[]{trustManager}, null);
61 | return sc;
62 | }
63 |
64 | /**
65 | * for ignoring verify SSL
66 | */
67 | public static CloseableHttpClient createClient() throws KeyManagementException, NoSuchAlgorithmException {
68 | SSLContext sslcontext = createIgnoreVerifySSL();
69 |
70 | RegistryHuaweiCredential
instance.
50 | */
51 | public HuaweiCredential getCredential() {
52 | return credential;
53 | }
54 |
55 | /**
56 | * Returns a instance of httpclient used for sending http request.
57 | *
58 | * @return A httpclient
instance.
59 | */
60 | public CloseableHttpClient getHttpClient() {
61 | return httpClient;
62 | }
63 |
64 | public ThreadManager getThreadManager() {
65 | return threadManager;
66 | }
67 |
68 | /**
69 | * Builder for constructing {@link HuaweiOption}.
70 | */
71 | public static Builder builder() {
72 | return new Builder();
73 | }
74 |
75 | public static final class Builder {
76 | private HuaweiCredential credential;
77 | private CloseableHttpClient httpClient;
78 |
79 | {
80 | try {
81 | httpClient = IgnoreSSLUtils.createClient();
82 | } catch (KeyManagementException | NoSuchAlgorithmException e) {
83 | logger.debug("Fail to create httpClient for sending message", e);
84 | }
85 | }
86 |
87 | private ThreadManager threadManager = HuaweiThreadManager.DEFAULT_THREAD_MANAGER;
88 |
89 |
90 | public Builder() {}
91 |
92 | public Builder setCredential(HuaweiCredential credential) {
93 | this.credential = credential;
94 | return this;
95 | }
96 |
97 | public Builder setHttpClient(CloseableHttpClient httpClient) {
98 | this.httpClient = httpClient;
99 | return this;
100 | }
101 |
102 | public Builder setThreadManager(ThreadManager threadManager) {
103 | this.threadManager = threadManager;
104 | return this;
105 | }
106 |
107 | public HuaweiOption build() {
108 | return new HuaweiOption(this);
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/messaging/HuaweiScheduledExecutor.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2017 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 |
15 | * 2019.12.15-Changed constructor HuaweiScheduledExecutor
16 | * Huawei Technologies Co., Ltd.
17 | *
18 | */
19 | package com.huawei.push.messaging;
20 |
21 | import com.google.common.base.Strings;
22 | import com.google.common.util.concurrent.ThreadFactoryBuilder;
23 |
24 | import java.util.concurrent.ScheduledThreadPoolExecutor;
25 | import java.util.concurrent.ThreadFactory;
26 |
27 | import static com.google.common.base.Preconditions.checkArgument;
28 |
29 | /**
30 | * A single-threaded scheduled executor implementation.
31 | */
32 | public class HuaweiScheduledExecutor extends ScheduledThreadPoolExecutor {
33 |
34 | public HuaweiScheduledExecutor(ThreadFactory threadFactory, String name) {
35 | this(threadFactory, name, null);
36 | }
37 |
38 | public HuaweiScheduledExecutor(ThreadFactory threadFactory, String name, Thread.UncaughtExceptionHandler handler) {
39 | super(1, decorateThreadFactory(threadFactory, name, handler));
40 | setRemoveOnCancelPolicy(true);
41 | }
42 |
43 | static ThreadFactory getThreadFactoryWithName(ThreadFactory threadFactory, String name) {
44 | return decorateThreadFactory(threadFactory, name, null);
45 | }
46 |
47 | private static ThreadFactory decorateThreadFactory(
48 | ThreadFactory threadFactory, String name, Thread.UncaughtExceptionHandler handler) {
49 | checkArgument(!Strings.isNullOrEmpty(name));
50 | ThreadFactoryBuilder builder = new ThreadFactoryBuilder()
51 | .setThreadFactory(threadFactory)
52 | .setNameFormat(name)
53 | .setDaemon(true);
54 | if (handler != null) {
55 | builder.setUncaughtExceptionHandler(handler);
56 | }
57 | return builder.build();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/messaging/HuaweiService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.huawei.push.messaging;
17 |
18 | /**
19 | * the services exposed from the HCM SDK
20 | * Each instance of the class is associated with one instance of the HuaweiApp
21 | */
22 | public abstract class HuaweiServiceExecutorService
instance.
48 | */
49 | protected abstract ExecutorService getExecutor(HuaweiApp app);
50 |
51 | /**
52 | * Cleans up the thread pool associated with an app.
53 | * This method is invoked when an app is deleted.
54 | *
55 | * @param app A {@link HuaweiApp} instance.
56 | * @return A non-null ExecutorService
instance.
57 | */
58 | protected abstract void releaseExecutor(HuaweiApp app, ExecutorService executor);
59 |
60 | /**
61 | * Returns the ThreadFactory
to be used for creating long-lived threads. This is
62 | * used mainly to create the long-lived worker threads for the scheduled (periodic) tasks started by the SDK.
63 | * The SDK guarantees clean termination of all threads started via this ThreadFactory
, when the user
64 | * calls {@link HuaweiApp#delete()}.
65 | *
66 | * ThreadFactory
.
70 | */
71 | protected abstract ThreadFactory getThreadFactory();
72 |
73 | static final class HuaweiExecutors {
74 | private ExecutorService userExecutor;
75 |
76 | private HuaweiExecutors(ExecutorService userExecutor) {
77 | ValidatorUtils.checkArgument(userExecutor != null, "ExecutorService must not be null");
78 | this.userExecutor = userExecutor;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/huawei/push/messaging/TokenRefresher.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2017 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 |
15 | * 2019.12.15-changed constructor TokenRefresher
16 | * Huawei Technologies Co., Ltd.
17 | *
18 | */
19 | package com.huawei.push.messaging;
20 |
21 | import com.huawei.push.util.ValidatorUtils;
22 | import org.apache.commons.lang3.StringUtils;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | import java.util.concurrent.Future;
27 |
28 | /**
29 | * Utility class for scheduling proactive token refresh events. Each HuaweiApp should have
30 | * its own instance of this class. TokenRefresher schedules token refresh events when token is expired.
31 | *
32 | *