| | |
| | | |
| | | private Map<String, String> extras; |
| | | |
| | | |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | |
| | | public void setAndroidHostPath(String androidHostPath) { |
| | | this.androidHostPath = androidHostPath; |
| | | } |
| | | |
| | | } |
| | |
| | | package com.ks.push.pojo.Query; |
| | | |
| | | import org.springframework.data.domain.Sort; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | public class BPushTaskQuery implements Serializable { |
| | | |
| | |
| | | public Date minStartPushTime; |
| | | public Date maxStartPushTime; |
| | | |
| | | public List<Sort.Order> sortList; |
| | | |
| | | |
| | | } |
| | |
| | | <dependency> |
| | | <groupId>com.yeshi</groupId> |
| | | <artifactId>utils</artifactId> |
| | | <version>0.0.6</version> |
| | | <version>0.1.0</version> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | |
| | | <dependency> |
| | | <groupId>com.yeshi</groupId> |
| | | <artifactId>utils</artifactId> |
| | | <version>0.0.6</version> |
| | | <version>0.1.0</version> |
| | | <!--<scope>compile</scope>--> |
| | | </dependency> |
| | | |
| | |
| | | <dependency> |
| | | <groupId>com.yeshi</groupId> |
| | | <artifactId>utils</artifactId> |
| | | <version>0.0.6</version> |
| | | <scope>compile</scope> |
| | | <version>0.1.1</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | |
| | | <version>2.1.2</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>redis.clients</groupId> |
| | | <artifactId>jedis</artifactId> |
| | | <version>3.2.0</version> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> |
| | | <dependency> |
| | | <groupId>org.apache.httpcomponents</groupId> |
| | | <artifactId>httpclient</artifactId> |
| | | <version>4.4.1</version> |
| | | </dependency> |
| | | |
| | | <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore --> |
| | | <dependency> |
| | | <groupId>org.apache.httpcomponents</groupId> |
| | | <artifactId>httpcore</artifactId> |
| | | <version>4.4.1</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.alibaba</groupId> |
| | | <artifactId>fastjson</artifactId> |
| | | <version>1.2.47</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.apache.commons</groupId> |
| | | <artifactId>commons-lang3</artifactId> |
| | | <version>3.8.1</version> |
| | | </dependency> |
| | | |
| | | |
| | | |
| | | <dependency> |
| | | <groupId>vpush</groupId> |
| | | <artifactId>vpush-server-sdk</artifactId> |
| | | <version>2.2</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>opush</groupId> |
| | | <artifactId>opush-server-sdk</artifactId> |
| | | <version>1.0.6</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>mipush</groupId> |
| | | <artifactId>MiPush_SDK_Server_Http</artifactId> |
| | | <version>1.0.11</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.googlecode.json-simple</groupId> |
| | | <artifactId>json-simple</artifactId> |
| | | <version>1.1.1</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.meizu.flyme</groupId> |
| | | <artifactId>push-server-sdk</artifactId> |
| | | <version>1.2.8.20190114_release</version> |
| | | </dependency> |
| | | |
| | | |
| | | |
| | | </dependencies> |
| | | |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.android; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.message.Notification; |
| | | import com.huawei.push.model.Importance; |
| | | import com.huawei.push.model.Visibility; |
| | | import com.huawei.push.util.CollectionUtils; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | |
| | | public class AndroidNotification { |
| | | |
| | | private static final String COLOR_PATTERN = "^#[0-9a-fA-F]{6}$"; |
| | | |
| | | private static final String URL_PATTERN = "^https.*"; |
| | | |
| | | private static final String VIBRATE_PATTERN = "[0-9]+|[0-9]+[sS]|[0-9]+[.][0-9]{1,9}|[0-9]+[.][0-9]{1,9}[sS]"; |
| | | |
| | | @JSONField(name = "title") |
| | | private String title; |
| | | |
| | | @JSONField(name = "body") |
| | | private String body; |
| | | |
| | | @JSONField(name = "icon") |
| | | private String icon; |
| | | |
| | | @JSONField(name = "color") |
| | | private String color; |
| | | |
| | | @JSONField(name = "sound") |
| | | private String sound; |
| | | |
| | | @JSONField(name = "default_sound") |
| | | private boolean defaultSound; |
| | | |
| | | @JSONField(name = "tag") |
| | | private String tag; |
| | | |
| | | @JSONField(name = "click_action") |
| | | private ClickAction clickAction; |
| | | |
| | | @JSONField(name = "body_loc_key") |
| | | private String bodyLocKey; |
| | | |
| | | @JSONField(name = "body_loc_args") |
| | | private List<String> bodyLocArgs = new ArrayList<>(); |
| | | |
| | | @JSONField(name = "title_loc_key") |
| | | private String titleLocKey; |
| | | |
| | | @JSONField(name = "title_loc_args") |
| | | private List<String> titleLocArgs = new ArrayList<>(); |
| | | |
| | | @JSONField(name = "multi_lang_key") |
| | | private JSONObject multiLangKey; |
| | | |
| | | @JSONField(name = "channel_id") |
| | | private String channelId; |
| | | |
| | | @JSONField(name = "notify_summary") |
| | | private String notifySummary; |
| | | |
| | | @JSONField(name = "image") |
| | | private String image; |
| | | |
| | | @JSONField(name = "style") |
| | | private Integer style; |
| | | |
| | | @JSONField(name = "big_title") |
| | | private String bigTitle; |
| | | |
| | | @JSONField(name = "big_body") |
| | | private String bigBody; |
| | | |
| | | @JSONField(name = "auto_clear") |
| | | private Integer autoClear; |
| | | |
| | | @JSONField(name = "notify_id") |
| | | private Integer notifyId; |
| | | |
| | | @JSONField(name = "group") |
| | | private String group; |
| | | |
| | | @JSONField(name = "badge") |
| | | private BadgeNotification badge; |
| | | |
| | | @JSONField(name = "ticker") |
| | | private String ticker; |
| | | |
| | | @JSONField(name = "auto_cancel") |
| | | private boolean autoCancel; |
| | | |
| | | @JSONField(name = "when") |
| | | private String when; |
| | | |
| | | @JSONField(name = "local_only") |
| | | private Boolean localOnly; |
| | | |
| | | @JSONField(name = "importance") |
| | | private String importance; |
| | | |
| | | @JSONField(name = "use_default_vibrate") |
| | | private boolean useDefaultVibrate; |
| | | |
| | | @JSONField(name = "use_default_light") |
| | | private boolean useDefaultLight; |
| | | |
| | | @JSONField(name = "vibrate_config") |
| | | private List<String> vibrateConfig = new ArrayList<>(); |
| | | |
| | | @JSONField(name = "visibility") |
| | | private String visibility; |
| | | |
| | | @JSONField(name = "light_settings") |
| | | private LightSettings lightSettings; |
| | | |
| | | @JSONField(name = "foreground_show") |
| | | private boolean foregroundShow; |
| | | |
| | | @JSONField(name = "inbox_content") |
| | | private List<String> inboxContent; |
| | | |
| | | @JSONField(name = "buttons") |
| | | private List<Button> buttons; |
| | | |
| | | private AndroidNotification(Builder builder) { |
| | | this.title = builder.title; |
| | | this.body = builder.body; |
| | | this.icon = builder.icon; |
| | | this.color = builder.color; |
| | | this.sound = builder.sound; |
| | | this.defaultSound = builder.defaultSound; |
| | | |
| | | this.tag = builder.tag; |
| | | this.clickAction = builder.clickAction; |
| | | |
| | | this.bodyLocKey = builder.bodyLocKey; |
| | | if (!CollectionUtils.isEmpty(builder.bodyLocArgs)) { |
| | | this.bodyLocArgs.addAll(builder.bodyLocArgs); |
| | | } else { |
| | | this.bodyLocArgs = null; |
| | | } |
| | | |
| | | this.titleLocKey = builder.titleLocKey; |
| | | if (!CollectionUtils.isEmpty(builder.titleLocArgs)) { |
| | | this.titleLocArgs.addAll(builder.titleLocArgs); |
| | | } else { |
| | | this.titleLocArgs = null; |
| | | } |
| | | |
| | | if (builder.multiLangkey != null) { |
| | | this.multiLangKey = builder.multiLangkey; |
| | | } else { |
| | | this.multiLangKey = null; |
| | | } |
| | | |
| | | this.channelId = builder.channelId; |
| | | |
| | | this.notifySummary = builder.notifySummary; |
| | | this.image = builder.image; |
| | | this.style = builder.style; |
| | | this.bigTitle = builder.bigTitle; |
| | | this.bigBody = builder.bigBody; |
| | | this.autoClear = builder.autoClear; |
| | | this.notifyId = builder.notifyId; |
| | | this.group = builder.group; |
| | | |
| | | if (null != builder.badge) { |
| | | this.badge = builder.badge; |
| | | } else { |
| | | this.badge = null; |
| | | } |
| | | |
| | | this.ticker = builder.ticker; |
| | | this.autoCancel = builder.autoCancel; |
| | | this.when = builder.when; |
| | | this.importance = builder.importance; |
| | | this.useDefaultVibrate = builder.useDefaultVibrate; |
| | | this.useDefaultLight = builder.useDefaultLight; |
| | | if (!CollectionUtils.isEmpty(builder.vibrateConfig)) { |
| | | this.vibrateConfig = builder.vibrateConfig; |
| | | } else { |
| | | this.vibrateConfig = null; |
| | | } |
| | | |
| | | this.visibility = builder.visibility; |
| | | this.lightSettings = builder.lightSettings; |
| | | this.foregroundShow = builder.foregroundShow; |
| | | |
| | | if (!CollectionUtils.isEmpty(builder.inboxContent)) { |
| | | this.inboxContent = builder.inboxContent; |
| | | } else { |
| | | this.inboxContent = null; |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(builder.buttons)) { |
| | | this.buttons = builder.buttons; |
| | | } else { |
| | | this.buttons = null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * check androidNotification's parameters |
| | | * |
| | | * @param notification which is in message |
| | | */ |
| | | public void check(Notification notification) { |
| | | if (null != notification) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(notification.getTitle()) || StringUtils.isNotEmpty(this.title), "title should be set"); |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(notification.getBody()) || StringUtils.isNotEmpty(this.body), "body should be set"); |
| | | } |
| | | |
| | | if (StringUtils.isNotEmpty(this.color)) { |
| | | ValidatorUtils.checkArgument(this.color.matches(AndroidNotification.COLOR_PATTERN), "Wrong color format, color must be in the form #RRGGBB"); |
| | | } |
| | | |
| | | if (this.clickAction != null) { |
| | | this.clickAction.check(); |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(this.bodyLocArgs)) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.bodyLocKey), "bodyLocKey is required when specifying bodyLocArgs"); |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(this.titleLocArgs)) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.titleLocKey), "titleLocKey is required when specifying titleLocArgs"); |
| | | } |
| | | |
| | | if (StringUtils.isNotEmpty(this.image)) { |
| | | ValidatorUtils.checkArgument(this.image.matches(URL_PATTERN), "notifyIcon must start with https"); |
| | | } |
| | | |
| | | //Style 0,1,2 |
| | | if (this.style != null) { |
| | | boolean isTrue = this.style == 0 || |
| | | this.style == 1 || |
| | | this.style == 2 || |
| | | this.style == 3; |
| | | ValidatorUtils.checkArgument(isTrue, "style should be one of 0:default, 1: big text, 2: big picture"); |
| | | |
| | | if (this.style == 1) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.bigTitle) && StringUtils.isNotEmpty(this.bigBody), "title and body are required when style = 1"); |
| | | } else if (this.style == 3) { |
| | | ValidatorUtils.checkArgument(!CollectionUtils.isEmpty(this.inboxContent) && this.inboxContent.size() <= 5, "inboxContent is required when style = 3 and at most 5 inbox content is needed"); |
| | | } |
| | | } |
| | | |
| | | if (this.autoClear != null) { |
| | | ValidatorUtils.checkArgument(this.autoClear.intValue() > 0, "auto clear should positive value"); |
| | | } |
| | | |
| | | if (badge != null) { |
| | | this.badge.check(); |
| | | } |
| | | |
| | | if (this.importance != null) { |
| | | ValidatorUtils.checkArgument(StringUtils.equals(this.importance, Importance.LOW.getValue()) |
| | | || StringUtils.equals(this.importance, Importance.NORMAL.getValue()) |
| | | || StringUtils.equals(this.importance, Importance.HIGH.getValue()), |
| | | "importance shouid be [HIGH, NORMAL, LOW]"); |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(this.vibrateConfig)) { |
| | | ValidatorUtils.checkArgument(this.vibrateConfig.size() <= 10, "vibrate_config array size cannot be more than 10"); |
| | | for (String vibrateTiming : this.vibrateConfig) { |
| | | ValidatorUtils.checkArgument(vibrateTiming.matches(AndroidNotification.VIBRATE_PATTERN), "Wrong vibrate timing format"); |
| | | long vibrateTimingValue = (long) (1000 * Double |
| | | .valueOf(StringUtils.substringBefore(vibrateTiming.toLowerCase(Locale.getDefault()), "s"))); |
| | | ValidatorUtils.checkArgument(vibrateTimingValue > 0 && vibrateTimingValue < 60000, "Vibrate timing duration must be greater than 0 and less than 60s"); |
| | | } |
| | | } |
| | | |
| | | if (this.visibility != null) { |
| | | ValidatorUtils.checkArgument(StringUtils.equals(this.visibility, Visibility.VISIBILITY_UNSPECIFIED.getValue()) |
| | | || StringUtils.equals(this.visibility, Visibility.PRIVATE.getValue()) |
| | | || StringUtils.equals(this.visibility, Visibility.PUBLIC.getValue()) |
| | | || StringUtils.equals(this.visibility, Visibility.SECRET.getValue()), |
| | | "visibility shouid be [VISIBILITY_UNSPECIFIED, PRIVATE, PUBLIC, SECRET]"); |
| | | } |
| | | |
| | | // multiLangKey |
| | | if (null != this.multiLangKey) { |
| | | Iterator<String> keyIterator = this.multiLangKey.keySet().iterator(); |
| | | while (keyIterator.hasNext()) { |
| | | String key = keyIterator.next(); |
| | | ValidatorUtils.checkArgument((this.multiLangKey.get(key) instanceof JSONObject), "multiLangKey value should be JSONObject"); |
| | | JSONObject contentsObj = multiLangKey.getJSONObject(key); |
| | | if (contentsObj != null) { |
| | | ValidatorUtils.checkArgument(contentsObj.keySet().size() <= 3, "Only three lang property can carry"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (this.lightSettings != null) { |
| | | this.lightSettings.check(); |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(this.buttons)) { |
| | | ValidatorUtils.checkArgument(this.buttons.size() <= 3, "Only three buttons can carry"); |
| | | for (Button button : this.buttons) { |
| | | button.check(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * getter |
| | | */ |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public String getBody() { |
| | | return body; |
| | | } |
| | | |
| | | public String getIcon() { |
| | | return icon; |
| | | } |
| | | |
| | | public String getColor() { |
| | | return color; |
| | | } |
| | | |
| | | public String getSound() { |
| | | return sound; |
| | | } |
| | | |
| | | public Boolean isDefaultSound() { |
| | | return defaultSound; |
| | | } |
| | | |
| | | public String getTag() { |
| | | return tag; |
| | | } |
| | | |
| | | public ClickAction getClickAction() { |
| | | return clickAction; |
| | | } |
| | | |
| | | public String getBodyLocKey() { |
| | | return bodyLocKey; |
| | | } |
| | | |
| | | public List<String> getBodyLocArgs() { |
| | | return bodyLocArgs; |
| | | } |
| | | |
| | | public String getTitleLocKey() { |
| | | return titleLocKey; |
| | | } |
| | | |
| | | public List<String> getTitleLocArgs() { |
| | | return titleLocArgs; |
| | | } |
| | | |
| | | public JSONObject getMultiLangKey() { |
| | | return multiLangKey; |
| | | } |
| | | |
| | | public String getChannelId() { |
| | | return channelId; |
| | | } |
| | | |
| | | public String getNotifySummary() { |
| | | return notifySummary; |
| | | } |
| | | |
| | | public String getImage() { |
| | | return image; |
| | | } |
| | | |
| | | public Integer getStyle() { |
| | | return style; |
| | | } |
| | | |
| | | public String getBigTitle() { |
| | | return bigTitle; |
| | | } |
| | | |
| | | public String getBigBody() { |
| | | return bigBody; |
| | | } |
| | | |
| | | public Integer getAutoClear() { |
| | | return autoClear; |
| | | } |
| | | |
| | | public Integer getNotifyId() { |
| | | return notifyId; |
| | | } |
| | | |
| | | public String getGroup() { |
| | | return group; |
| | | } |
| | | |
| | | public BadgeNotification getBadge() { |
| | | return badge; |
| | | } |
| | | |
| | | public String getTicker() { |
| | | return ticker; |
| | | } |
| | | |
| | | public String getWhen() { |
| | | return when; |
| | | } |
| | | |
| | | public String getImportance() { |
| | | return importance; |
| | | } |
| | | |
| | | public List<String> getVibrateConfig() { |
| | | return vibrateConfig; |
| | | } |
| | | |
| | | public String getVisibility() { |
| | | return visibility; |
| | | } |
| | | |
| | | public LightSettings getLightSettings() { |
| | | return lightSettings; |
| | | } |
| | | |
| | | public boolean isAutoCancel() { |
| | | return autoCancel; |
| | | } |
| | | |
| | | public Boolean getLocalOnly() { |
| | | return localOnly; |
| | | } |
| | | |
| | | public boolean isUseDefaultVibrate() { |
| | | return useDefaultVibrate; |
| | | } |
| | | |
| | | public boolean isUseDefaultLight() { |
| | | return useDefaultLight; |
| | | } |
| | | |
| | | public boolean isForegroundShow() { |
| | | return foregroundShow; |
| | | } |
| | | |
| | | public List<String> getInboxContent() { |
| | | return inboxContent; |
| | | } |
| | | |
| | | public List<Button> getButtons() { |
| | | return buttons; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | * |
| | | * @return |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | |
| | | private String title; |
| | | private String body; |
| | | private String icon; |
| | | private String color; |
| | | private String sound; |
| | | private boolean defaultSound; |
| | | private String tag; |
| | | private ClickAction clickAction; |
| | | private String bodyLocKey; |
| | | private List<String> bodyLocArgs = new ArrayList<>(); |
| | | private String titleLocKey; |
| | | private List<String> titleLocArgs = new ArrayList<>(); |
| | | private JSONObject multiLangkey; |
| | | private String channelId; |
| | | private String notifySummary; |
| | | private String image; |
| | | private Integer style; |
| | | private String bigTitle; |
| | | private String bigBody; |
| | | private Integer autoClear; |
| | | private Integer notifyId; |
| | | private String group; |
| | | |
| | | private BadgeNotification badge; |
| | | |
| | | private String ticker; |
| | | private boolean autoCancel = true; |
| | | private String when; |
| | | private String importance; |
| | | private boolean useDefaultVibrate; |
| | | private boolean useDefaultLight; |
| | | private List<String> vibrateConfig = new ArrayList<>(); |
| | | private String visibility; |
| | | private LightSettings lightSettings; |
| | | private boolean foregroundShow; |
| | | |
| | | private List<String> inboxContent = new ArrayList<>(); |
| | | private List<Button> buttons = new ArrayList<Button>(); |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setTitle(String title) { |
| | | this.title = title; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBody(String body) { |
| | | this.body = body; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setIcon(String icon) { |
| | | this.icon = icon; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setColor(String color) { |
| | | this.color = color; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setSound(String sound) { |
| | | this.sound = sound; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setDefaultSound(boolean defaultSound) { |
| | | this.defaultSound = defaultSound; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTag(String tag) { |
| | | this.tag = tag; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setClickAction(ClickAction clickAction) { |
| | | this.clickAction = clickAction; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBodyLocKey(String bodyLocKey) { |
| | | this.bodyLocKey = bodyLocKey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addBodyLocArgs(String arg) { |
| | | this.bodyLocArgs.add(arg); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllBodyLocArgs(List<String> args) { |
| | | this.bodyLocArgs.addAll(args); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTitleLocKey(String titleLocKey) { |
| | | this.titleLocKey = titleLocKey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addTitleLocArgs(String arg) { |
| | | this.titleLocArgs.add(arg); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllTitleLocArgs(List<String> args) { |
| | | this.titleLocArgs.addAll(args); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setMultiLangkey(JSONObject multiLangkey) { |
| | | this.multiLangkey = multiLangkey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setChannelId(String channelId) { |
| | | this.channelId = channelId; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setNotifySummary(String notifySummary) { |
| | | this.notifySummary = notifySummary; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setImage(String image) { |
| | | this.image = image; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setStyle(Integer style) { |
| | | this.style = style; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBigTitle(String bigTitle) { |
| | | this.bigTitle = bigTitle; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBigBody(String bigBody) { |
| | | this.bigBody = bigBody; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAutoClear(Integer autoClear) { |
| | | this.autoClear = autoClear; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setNotifyId(Integer notifyId) { |
| | | this.notifyId = notifyId; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setGroup(String group) { |
| | | this.group = group; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBadge(BadgeNotification badge) { |
| | | this.badge = badge; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTicker(String ticker) { |
| | | this.ticker = ticker; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAutoCancel(boolean autoCancel) { |
| | | this.autoCancel = autoCancel; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWhen(String when) { |
| | | this.when = when; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setImportance(String importance) { |
| | | this.importance = importance; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setUseDefaultVibrate(boolean useDefaultVibrate) { |
| | | this.useDefaultVibrate = useDefaultVibrate; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setUseDefaultLight(boolean useDefaultLight) { |
| | | this.useDefaultLight = useDefaultLight; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addVibrateConfig(String vibrateTiming) { |
| | | this.vibrateConfig.add(vibrateTiming); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | public Builder addAllVibrateConfig(List<String> vibrateTimings) { |
| | | this.vibrateConfig.addAll(vibrateTimings); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setVisibility(String visibility) { |
| | | this.visibility = visibility; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setLightSettings(LightSettings lightSettings) { |
| | | this.lightSettings = lightSettings; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setForegroundShow(boolean foregroundShow) { |
| | | this.foregroundShow = foregroundShow; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addInboxContent(String inboxContent) { |
| | | this.inboxContent.add(inboxContent); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllInboxContent(List<String> inboxContents) { |
| | | this.inboxContent.addAll(inboxContents); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addButton(Button button) { |
| | | this.buttons.add(button); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllButtons(List<Button> buttons) { |
| | | this.buttons.addAll(buttons); |
| | | return this; |
| | | } |
| | | |
| | | public AndroidNotification build() { |
| | | return new AndroidNotification(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.android; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class BadgeNotification { |
| | | @JSONField(name = "add_num") |
| | | private Integer addNum; |
| | | |
| | | @JSONField(name = "class") |
| | | private String badgeClass; |
| | | |
| | | @JSONField(name = "set_num") |
| | | private Integer setNum; |
| | | |
| | | public Integer getAddNum() { |
| | | return addNum; |
| | | } |
| | | |
| | | public String getBadgeClass() { |
| | | return badgeClass; |
| | | } |
| | | |
| | | public Integer getSetNum() { |
| | | return setNum; |
| | | } |
| | | |
| | | public BadgeNotification(Integer addNum, String badgeClass) { |
| | | this.addNum = builder().addNum; |
| | | this.badgeClass = badgeClass; |
| | | } |
| | | |
| | | public BadgeNotification(Builder builder) { |
| | | this.addNum = builder.addNum; |
| | | this.badgeClass = builder.badgeClass; |
| | | this.setNum = builder.setNum; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.addNum != null) { |
| | | ValidatorUtils.checkArgument(this.addNum.intValue() > 0 && this.addNum.intValue() < 100, "add_num should locate between 0 and 100"); |
| | | } |
| | | if (this.setNum != null) { |
| | | ValidatorUtils.checkArgument(this.setNum.intValue() >= 0 && this.setNum.intValue() < 100, "set_num should locate between 0 and 100"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Integer addNum; |
| | | |
| | | private String badgeClass; |
| | | |
| | | private Integer setNum; |
| | | |
| | | public Builder setAddNum(Integer addNum) { |
| | | this.addNum = addNum; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setSetNum(Integer setNum) { |
| | | this.setNum = setNum; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBadgeClass(String badgeClass) { |
| | | this.badgeClass = badgeClass; |
| | | return this; |
| | | } |
| | | |
| | | public BadgeNotification build() { |
| | | return new BadgeNotification(this); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (c) Huawei Technologies Co., Ltd. 2019-2029. All rights reserved. |
| | | */ |
| | | |
| | | package com.huawei.push.android; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | /** |
| | | * 功能描述 |
| | | * |
| | | * @author l00282963 |
| | | * @since 2020-01-19 |
| | | */ |
| | | public class Button { |
| | | @JSONField(name = "name") |
| | | private String name; |
| | | |
| | | @JSONField(name = "action_type") |
| | | private Integer actionType; |
| | | |
| | | @JSONField(name = "intent_type") |
| | | private Integer intentType; |
| | | |
| | | @JSONField(name = "intent") |
| | | private String intent; |
| | | |
| | | @JSONField(name = "data") |
| | | private String data; |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public Integer getActionType() { |
| | | return actionType; |
| | | } |
| | | |
| | | public Integer getIntentType() { |
| | | return intentType; |
| | | } |
| | | |
| | | public String getIntent() { |
| | | return intent; |
| | | } |
| | | |
| | | public String getData() { |
| | | return data; |
| | | } |
| | | |
| | | |
| | | public Button(Builder builder) { |
| | | this.name = builder.name; |
| | | this.actionType = builder.actionType; |
| | | this.intentType = builder.intentType; |
| | | this.intent = builder.intent; |
| | | this.data = builder.data; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.actionType != null && this.actionType == 4) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.data), "data is needed when actionType is 4"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | @JSONField(name = "name") |
| | | private String name; |
| | | |
| | | @JSONField(name = "actionType") |
| | | private Integer actionType; |
| | | |
| | | @JSONField(name = "intentType") |
| | | private Integer intentType; |
| | | |
| | | @JSONField(name = "intent") |
| | | private String intent; |
| | | |
| | | @JSONField(name = "data") |
| | | private String data; |
| | | |
| | | public Builder setName(String name) { |
| | | this.name = name; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setActionType(Integer actionType) { |
| | | this.actionType = actionType; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setIntentType(Integer intentType) { |
| | | this.intentType = intentType; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setIntent(String intent) { |
| | | this.intent = intent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setData(String data) { |
| | | this.data = data; |
| | | return this; |
| | | } |
| | | |
| | | public Button build() { |
| | | return new Button(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.android; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | public class ClickAction { |
| | | private static final String PATTERN = "^https.*"; |
| | | |
| | | @JSONField(name = "type") |
| | | private Integer type; |
| | | |
| | | @JSONField(name = "intent") |
| | | private String intent; |
| | | |
| | | @JSONField(name = "url") |
| | | private String url; |
| | | |
| | | @JSONField(name = "rich_resource") |
| | | private String richResource; |
| | | |
| | | @JSONField(name = "action") |
| | | private String action; |
| | | |
| | | private ClickAction(Builder builder) { |
| | | this.type = builder.type; |
| | | switch (this.type) { |
| | | case 1: |
| | | this.intent = builder.intent; |
| | | this.action = builder.action; |
| | | break; |
| | | case 2: |
| | | this.url = builder.url; |
| | | break; |
| | | case 4: |
| | | this.richResource = builder.richResource; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * check clickAction's parameters |
| | | */ |
| | | public void check() { |
| | | boolean isTrue = this.type == 1 || |
| | | this.type == 2 || |
| | | this.type == 3 || |
| | | this.type == 4; |
| | | ValidatorUtils.checkArgument(isTrue, "click type should be one of 1: customize action, 2: open url, 3: open app, 4: open rich media"); |
| | | |
| | | switch (this.type) { |
| | | case 1: |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.intent) || StringUtils.isNotEmpty(this.action), "intent or action is required when click type=1"); |
| | | break; |
| | | case 2: |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.url), "url is required when click type=2"); |
| | | ValidatorUtils.checkArgument(this.url.matches(PATTERN), "url must start with https"); |
| | | break; |
| | | case 4: |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.richResource), "richResource is required when click type=4"); |
| | | ValidatorUtils.checkArgument(this.richResource.matches(PATTERN), "richResource must start with https"); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * getter |
| | | */ |
| | | public int getType() { |
| | | return type; |
| | | } |
| | | |
| | | public String getIntent() { |
| | | return intent; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public String getRichResource() { |
| | | return richResource; |
| | | } |
| | | |
| | | public String getAction() { |
| | | return action; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Integer type; |
| | | private String intent; |
| | | private String url; |
| | | private String richResource; |
| | | private String action; |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setType(Integer type) { |
| | | this.type = type; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setIntent(String intent) { |
| | | this.intent = intent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setUrl(String url) { |
| | | this.url = url; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setRichResource(String richResource) { |
| | | this.richResource = richResource; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAction(String action) { |
| | | this.action = action; |
| | | return this; |
| | | } |
| | | |
| | | public ClickAction build() { |
| | | return new ClickAction(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.android; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class Color { |
| | | private final float zero = -0.000001f; |
| | | |
| | | private final float one = 1.000001f; |
| | | |
| | | @JSONField(name = "alpha") |
| | | private Float alpha = new Float(1.0); |
| | | |
| | | @JSONField(name = "red") |
| | | private Float red = new Float(0.0); |
| | | |
| | | @JSONField(name = "green") |
| | | private Float green = new Float(0.0); |
| | | |
| | | @JSONField(name = "blue") |
| | | private Float blue = new Float(0.0); |
| | | |
| | | public Color(Builder builder) { |
| | | this.alpha = builder.alpha; |
| | | this.red = builder.red; |
| | | this.green = builder.green; |
| | | this.blue = builder.blue; |
| | | } |
| | | |
| | | public double getAlpha() { |
| | | return alpha; |
| | | } |
| | | |
| | | public Float getRed() { |
| | | return red; |
| | | } |
| | | |
| | | public Float getGreen() { |
| | | return green; |
| | | } |
| | | |
| | | public Float getBlue() { |
| | | return blue; |
| | | } |
| | | |
| | | public void check() { |
| | | ValidatorUtils.checkArgument(this.alpha > zero && this.alpha < one, "Alpha shoube locate between [0,1]"); |
| | | ValidatorUtils.checkArgument(this.red > zero && this.red < one, "Red shoube locate between [0,1]"); |
| | | ValidatorUtils.checkArgument(this.green > zero && this.green < one, "Green shoube locate between [0,1]"); |
| | | ValidatorUtils.checkArgument(this.blue > zero && this.blue < one, "Blue shoube locate between [0,1]"); |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Float alpha = new Float(1.0); |
| | | private Float red = new Float(0.0); |
| | | private Float green = new Float(0.0); |
| | | private Float blue = new Float(0.0); |
| | | |
| | | public Builder setAlpha(Float alpha) { |
| | | this.alpha = alpha; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setRed(Float red) { |
| | | this.red = red; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setGreen(Float green) { |
| | | this.green = green; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBlue(Float blue) { |
| | | this.blue = blue; |
| | | return this; |
| | | } |
| | | |
| | | public Color build() { |
| | | return new Color(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.android; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class LightSettings { |
| | | private static final String LIGTH_DURATION_PATTERN = "\\d+|\\d+[sS]|\\d+.\\d{1,9}|\\d+.\\d{1,9}[sS]"; |
| | | |
| | | @JSONField(name = "color") |
| | | private Color color; |
| | | |
| | | @JSONField(name = "light_on_duration") |
| | | private String lightOnDuration; |
| | | |
| | | @JSONField(name = "light_off_duration") |
| | | private String lightOffDuration; |
| | | |
| | | public LightSettings(Builder builder) { |
| | | this.color = builder.color; |
| | | this.lightOnDuration = builder.lightOnDuration; |
| | | this.lightOffDuration = builder.lightOffDuration; |
| | | } |
| | | |
| | | public Color getColor() { |
| | | return color; |
| | | } |
| | | |
| | | public String getLightOnDuration() { |
| | | return lightOnDuration; |
| | | } |
| | | |
| | | public String getLightOffDuration() { |
| | | return lightOffDuration; |
| | | } |
| | | |
| | | /** |
| | | * 参数校验 |
| | | */ |
| | | public void check() { |
| | | ValidatorUtils.checkArgument(this.color != null, "color must be selected when light_settings is set"); |
| | | |
| | | if (this.color != null) { |
| | | this.color.check(); |
| | | } |
| | | |
| | | ValidatorUtils.checkArgument(this.lightOnDuration != null, "light_on_duration must be selected when light_settings is set"); |
| | | |
| | | ValidatorUtils.checkArgument(this.lightOffDuration != null, "light_off_duration must be selected when light_settings is set"); |
| | | |
| | | ValidatorUtils.checkArgument(this.lightOnDuration.matches(LIGTH_DURATION_PATTERN), "light_on_duration format is wrong"); |
| | | |
| | | ValidatorUtils.checkArgument(this.lightOffDuration.matches(LIGTH_DURATION_PATTERN), "light_off_duration format is wrong"); |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Color color; |
| | | private String lightOnDuration; |
| | | private String lightOffDuration; |
| | | |
| | | public Builder setColor(Color color) { |
| | | this.color = color; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setLightOnDuration(String lightOnDuration) { |
| | | this.lightOnDuration = lightOnDuration; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setLightOffDuration(String lightOffDuration) { |
| | | this.lightOffDuration = lightOffDuration; |
| | | return this; |
| | | } |
| | | |
| | | public LightSettings build() { |
| | | return new LightSettings(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.apns; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.CollectionUtils; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | public class Alert { |
| | | @JSONField(name = "title") |
| | | private String title; |
| | | |
| | | @JSONField(name = "body") |
| | | private String body; |
| | | |
| | | @JSONField(name = "title-loc-key") |
| | | private String titleLocKey; |
| | | |
| | | @JSONField(name = "title-loc-args") |
| | | private List<String> titleLocArgs = new ArrayList<String>(); |
| | | |
| | | @JSONField(name = "action-loc-key") |
| | | private String actionLocKey; |
| | | |
| | | @JSONField(name = "loc-key") |
| | | private String locKey; |
| | | |
| | | @JSONField(name = "loc-args") |
| | | private List<String> locArgs = new ArrayList<String>(); |
| | | |
| | | @JSONField(name = "launch-image") |
| | | private String launchImage; |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public String getBody() { |
| | | return body; |
| | | } |
| | | |
| | | public String getTitleLocKey() { |
| | | return titleLocKey; |
| | | } |
| | | |
| | | public List<String> getTitleLocArgs() { |
| | | return titleLocArgs; |
| | | } |
| | | |
| | | public String getActionLocKey() { |
| | | return actionLocKey; |
| | | } |
| | | |
| | | public String getLocKey() { |
| | | return locKey; |
| | | } |
| | | |
| | | public List<String> getLocArgs() { |
| | | return locArgs; |
| | | } |
| | | |
| | | public String getLaunchImage() { |
| | | return launchImage; |
| | | } |
| | | |
| | | private Alert(Builder builder) { |
| | | this.title = builder.title; |
| | | this.body = builder.body; |
| | | this.titleLocKey = builder.titleLocKey; |
| | | if (!CollectionUtils.isEmpty(builder.titleLocArgs)) { |
| | | this.titleLocArgs.addAll(builder.titleLocArgs); |
| | | } else { |
| | | this.titleLocArgs = null; |
| | | } |
| | | this.actionLocKey = builder.actionLocKey; |
| | | this.locKey = builder.locKey; |
| | | if (!CollectionUtils.isEmpty(builder.locArgs)) { |
| | | this.locArgs.addAll(builder.locArgs); |
| | | } else { |
| | | this.locArgs = null; |
| | | } |
| | | this.launchImage = builder.launchImage; |
| | | } |
| | | |
| | | public void check() { |
| | | if (!CollectionUtils.isEmpty(this.locArgs)) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.locKey), "locKey is required when specifying locArgs"); |
| | | } |
| | | if (!CollectionUtils.isEmpty(this.titleLocArgs)) { |
| | | ValidatorUtils.checkArgument(StringUtils.isNotEmpty(this.titleLocKey), "titleLocKey is required when specifying titleLocArgs"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | * |
| | | * @return |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String title; |
| | | private String body; |
| | | private String titleLocKey; |
| | | private List<String> titleLocArgs = new ArrayList<String>(); |
| | | private String actionLocKey; |
| | | private String locKey; |
| | | private List<String> locArgs = new ArrayList<String>(); |
| | | private String launchImage; |
| | | |
| | | public Builder setTitle(String title) { |
| | | this.title = title; |
| | | return this; |
| | | |
| | | } |
| | | |
| | | public Builder setBody(String body) { |
| | | this.body = body; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTitleLocKey(String titleLocKey) { |
| | | this.titleLocKey = titleLocKey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAddAllTitleLocArgs(List<String> titleLocArgs) { |
| | | this.titleLocArgs.addAll(titleLocArgs); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAddTitleLocArg(String titleLocArg) { |
| | | this.titleLocArgs.add(titleLocArg); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setActionLocKey(String actionLocKey) { |
| | | this.actionLocKey = actionLocKey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setLocKey(String locKey) { |
| | | this.locKey = locKey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder AddAllLocArgs(List<String> locArgs) { |
| | | this.locArgs.addAll(locArgs); |
| | | return this; |
| | | } |
| | | |
| | | public Builder AddLocArg(String locArg) { |
| | | this.locArgs.add(locArg); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setLaunchImage(String launchImage) { |
| | | this.launchImage = launchImage; |
| | | return this; |
| | | } |
| | | |
| | | public Alert build() { |
| | | return new Alert(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.apns; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class ApnsHeaders { |
| | | private static final String AUTHORIZATION_PATTERN = "^bearer*"; |
| | | |
| | | private static final String APN_ID_PATTERN = "[0-9a-z]{8}(-[0-9a-z]{4}){3}-[0-9a-z]{12}"; |
| | | |
| | | private static final int SEND_IMMEDIATELY = 10; |
| | | |
| | | private static final int SEND_BY_GROUP = 5; |
| | | |
| | | @JSONField(name = "authorization") |
| | | private String authorization; |
| | | |
| | | @JSONField(name = "apns-id") |
| | | private String apnsId; |
| | | |
| | | @JSONField(name = "apns-expiration") |
| | | private Long apnsExpiration; |
| | | |
| | | @JSONField(name = "apns-priority") |
| | | private String apnsPriority; |
| | | |
| | | @JSONField(name = "apns-topic") |
| | | private String apnsTopic; |
| | | |
| | | @JSONField(name = "apns-collapse-id") |
| | | private String apnsCollapseId; |
| | | |
| | | public String getAuthorization() { |
| | | return authorization; |
| | | } |
| | | |
| | | public String getApnsId() { |
| | | return apnsId; |
| | | } |
| | | |
| | | public Long getApnsExpiration() { |
| | | return apnsExpiration; |
| | | } |
| | | |
| | | public String getApnsPriority() { |
| | | return apnsPriority; |
| | | } |
| | | |
| | | public String getApnsTopic() { |
| | | return apnsTopic; |
| | | } |
| | | |
| | | public String getApnsCollapseId() { |
| | | return apnsCollapseId; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.authorization != null) { |
| | | ValidatorUtils.checkArgument(this.authorization.matches(AUTHORIZATION_PATTERN), "authorization must start with bearer"); |
| | | } |
| | | if (this.apnsId != null) { |
| | | ValidatorUtils.checkArgument(this.apnsId.matches(APN_ID_PATTERN), "apns-id format error"); |
| | | } |
| | | if (this.apnsPriority != null) { |
| | | ValidatorUtils.checkArgument(Integer.parseInt(this.apnsPriority) == SEND_BY_GROUP || |
| | | Integer.parseInt(this.apnsPriority) == SEND_IMMEDIATELY, "apns-priority should be SEND_BY_GROUP:5 or SEND_IMMEDIATELY:10"); |
| | | } |
| | | if (this.apnsCollapseId != null) { |
| | | ValidatorUtils.checkArgument(this.apnsCollapseId.getBytes().length < 64, "Number of apnsCollapseId bytes should be less than 64"); |
| | | } |
| | | } |
| | | |
| | | private ApnsHeaders(Builder builder) { |
| | | this.authorization = builder.authorization; |
| | | this.apnsId = builder.apnsId; |
| | | this.apnsExpiration = builder.apnsExpiration; |
| | | this.apnsPriority = builder.apnsPriority; |
| | | this.apnsTopic = builder.apnsTopic; |
| | | this.apnsCollapseId = builder.apnsCollapseId; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String authorization; |
| | | private String apnsId; |
| | | private Long apnsExpiration; |
| | | private String apnsPriority; |
| | | private String apnsTopic; |
| | | private String apnsCollapseId; |
| | | |
| | | public Builder setAuthorization(String authorization) { |
| | | this.authorization = authorization; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApnsId(String apnsId) { |
| | | this.apnsId = apnsId; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApnsExpiration(Long apnsExpiration) { |
| | | this.apnsExpiration = apnsExpiration; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApnsPriority(String apnsPriority) { |
| | | this.apnsPriority = apnsPriority; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApnsTopic(String apnsTopic) { |
| | | this.apnsTopic = apnsTopic; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApnsCollapseId(String apnsCollapseId) { |
| | | this.apnsCollapseId = apnsCollapseId; |
| | | return this; |
| | | } |
| | | |
| | | public ApnsHeaders build() { |
| | | return new ApnsHeaders(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.apns; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class ApnsHmsOptions { |
| | | private static final int TEST_USER = 1; |
| | | private static final int FORMAL_USER = 1; |
| | | private static final int VOIP_USER = 1; |
| | | |
| | | @JSONField(name = "target_user_type") |
| | | private Integer targetUserType; |
| | | |
| | | public Integer getTargetUserType() { |
| | | return targetUserType; |
| | | } |
| | | |
| | | private ApnsHmsOptions(Builder builder){ |
| | | this.targetUserType = builder.targetUserType; |
| | | } |
| | | |
| | | public void check(){ |
| | | if (targetUserType != null) { |
| | | ValidatorUtils.checkArgument(this.targetUserType.intValue() == TEST_USER |
| | | || this.targetUserType.intValue() == FORMAL_USER |
| | | || this.targetUserType.intValue() == VOIP_USER, |
| | | "targetUserType should be [TEST_USER: 1, FORMAL_USER: 2, VOIP_USER: 3]"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Integer targetUserType; |
| | | |
| | | public Builder setTargetUserType(Integer targetUserType) { |
| | | this.targetUserType = targetUserType; |
| | | return this; |
| | | } |
| | | |
| | | public ApnsHmsOptions build(){ |
| | | return new ApnsHmsOptions(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.apns; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class Aps { |
| | | @JSONField(name = "alert") |
| | | private Object alert; |
| | | |
| | | @JSONField(name = "badge") |
| | | private Integer badge; |
| | | |
| | | @JSONField(name = "sound") |
| | | private String sound; |
| | | |
| | | @JSONField(name = "content-available") |
| | | private Integer contentAvailable; |
| | | |
| | | @JSONField(name = "category") |
| | | private String category; |
| | | |
| | | @JSONField(name = "thread-id") |
| | | private String threadId; |
| | | |
| | | public Object getAlert() { |
| | | return alert; |
| | | } |
| | | |
| | | public Integer getBadge() { |
| | | return badge; |
| | | } |
| | | |
| | | public String getSound() { |
| | | return sound; |
| | | } |
| | | |
| | | public Integer getContentAvailable() { |
| | | return contentAvailable; |
| | | } |
| | | |
| | | public String getCategory() { |
| | | return category; |
| | | } |
| | | |
| | | public String getThreadId() { |
| | | return threadId; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.alert != null) { |
| | | if(this.alert instanceof Alert){ |
| | | ((Alert) this.alert).check(); |
| | | }else{ |
| | | ValidatorUtils.checkArgument((this.alert instanceof String), "Alter should be Dictionary or String"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Aps(Builder builder) { |
| | | this.alert = builder.alert; |
| | | this.badge = builder.badge; |
| | | this.sound = builder.sound; |
| | | this.contentAvailable = builder.contentAvailable; |
| | | this.category = builder.category; |
| | | this.threadId = builder.threadId; |
| | | } |
| | | |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Object alert; |
| | | private Integer badge; |
| | | private String sound; |
| | | private Integer contentAvailable; |
| | | private String category; |
| | | private String threadId; |
| | | |
| | | public Builder setAlert(Object alert) { |
| | | this.alert = alert; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBadge(Integer badge) { |
| | | this.badge = badge; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setSound(String sound) { |
| | | this.sound = sound; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setContentAvailable(Integer contentAvailable) { |
| | | this.contentAvailable = contentAvailable; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setCategory(String category) { |
| | | this.category = category; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setThreadId(String threadId) { |
| | | this.threadId = threadId; |
| | | return this; |
| | | } |
| | | |
| | | public Aps build() { |
| | | return new Aps(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.exception; |
| | | |
| | | import com.google.common.base.Strings; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | /** |
| | | * exceptions |
| | | */ |
| | | public class HuaweiException extends Exception { |
| | | |
| | | public HuaweiException(String detailMessage) { |
| | | super(detailMessage); |
| | | ValidatorUtils.checkArgument(!Strings.isNullOrEmpty(detailMessage), "Detail message must not be empty"); |
| | | } |
| | | |
| | | public HuaweiException(String detailMessage, Throwable cause) { |
| | | super(detailMessage, cause); |
| | | ValidatorUtils.checkArgument(!Strings.isNullOrEmpty(detailMessage), "Detail message must not be empty"); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.exception; |
| | | |
| | | import com.google.common.base.Strings; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | public class HuaweiMesssagingException extends HuaweiException { |
| | | private final String errorCode; |
| | | |
| | | public HuaweiMesssagingException(String errorCode, String message) { |
| | | super(message); |
| | | ValidatorUtils.checkArgument(!Strings.isNullOrEmpty(errorCode)); |
| | | this.errorCode = errorCode; |
| | | } |
| | | |
| | | public HuaweiMesssagingException(String errorCode, String message, Throwable cause) { |
| | | super(message, cause); |
| | | ValidatorUtils.checkArgument(!Strings.isNullOrEmpty(errorCode)); |
| | | this.errorCode = errorCode; |
| | | } |
| | | |
| | | public String getErrorCode() { |
| | | return errorCode; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.android.AndroidNotification; |
| | | import com.huawei.push.model.Urgency; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | public class AndroidConfig { |
| | | private static final String TTL_PATTERN = "\\d+|\\d+[sS]|\\d+.\\d{1,9}|\\d+.\\d{1,9}[sS]"; |
| | | |
| | | @JSONField(name = "collapse_key") |
| | | private Integer collapseKey; |
| | | |
| | | @JSONField(name = "urgency") |
| | | private String urgency; |
| | | |
| | | @JSONField(name = "category") |
| | | private String category; |
| | | |
| | | @JSONField(name = "ttl") |
| | | private String ttl; |
| | | |
| | | @JSONField(name = "bi_tag") |
| | | private String biTag; |
| | | |
| | | @JSONField(name = "fast_app_target") |
| | | private Integer fastAppTargetType; |
| | | |
| | | @JSONField(name = "data") |
| | | private String data; |
| | | |
| | | @JSONField(name = "notification") |
| | | private AndroidNotification notification; |
| | | |
| | | public AndroidConfig(Builder builder) { |
| | | this.collapseKey = builder.collapseKey; |
| | | this.urgency = builder.urgency; |
| | | this.category = builder.category; |
| | | |
| | | if (null != builder.ttl) { |
| | | this.ttl = builder.ttl; |
| | | } else { |
| | | this.ttl = null; |
| | | } |
| | | |
| | | this.biTag = builder.biTag; |
| | | this.fastAppTargetType = builder.fastAppTargetType; |
| | | this.data = builder.data; |
| | | this.notification = builder.notification; |
| | | } |
| | | |
| | | /** |
| | | * check androidConfig's parameters |
| | | * |
| | | * @param notification whcic is in message |
| | | */ |
| | | public void check(Notification notification) { |
| | | if (this.collapseKey != null) { |
| | | ValidatorUtils.checkArgument((this.collapseKey >= -1 && this.collapseKey <= 100), "Collapse Key should be [-1, 100]"); |
| | | } |
| | | |
| | | if (this.urgency != null) { |
| | | ValidatorUtils.checkArgument(StringUtils.equals(this.urgency, Urgency.HIGH.getValue()) |
| | | || StringUtils.equals(this.urgency, Urgency.NORMAL.getValue()), |
| | | "urgency shouid be [HIGH, NORMAL]"); |
| | | } |
| | | |
| | | if (StringUtils.isNotEmpty(this.ttl)) { |
| | | ValidatorUtils.checkArgument(this.ttl.matches(AndroidConfig.TTL_PATTERN), "The TTL's format is wrong"); |
| | | } |
| | | |
| | | if (this.fastAppTargetType != null) { |
| | | ValidatorUtils.checkArgument(this.fastAppTargetType == 1 || this.fastAppTargetType == 2, "Invalid fast app target type[one of 1 or 2]"); |
| | | } |
| | | |
| | | if (null != this.notification) { |
| | | this.notification.check(notification); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * getter |
| | | */ |
| | | public Integer getCollapseKey() { |
| | | return collapseKey; |
| | | } |
| | | |
| | | public String getTtl() { |
| | | return ttl; |
| | | } |
| | | |
| | | public String getCategory() { |
| | | return category; |
| | | } |
| | | |
| | | public String getBiTag() { |
| | | return biTag; |
| | | } |
| | | |
| | | public Integer getFastAppTargetType() { |
| | | return fastAppTargetType; |
| | | } |
| | | |
| | | public AndroidNotification getNotification() { |
| | | return notification; |
| | | } |
| | | |
| | | public String getUrgency() { |
| | | return urgency; |
| | | } |
| | | |
| | | public String getData() { |
| | | return data; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private Integer collapseKey; |
| | | private String urgency; |
| | | private String category; |
| | | private String ttl; |
| | | private String biTag; |
| | | private Integer fastAppTargetType; |
| | | private String data; |
| | | |
| | | private AndroidNotification notification; |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setCollapseKey(Integer collapseKey) { |
| | | this.collapseKey = collapseKey; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setUrgency(String urgency) { |
| | | this.urgency = urgency; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setCategory(String category) { |
| | | this.category = category; |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * time-to-live |
| | | */ |
| | | public Builder setTtl(String ttl) { |
| | | this.ttl = ttl; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBiTag(String biTag) { |
| | | this.biTag = biTag; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setFastAppTargetType(Integer fastAppTargetType) { |
| | | this.fastAppTargetType = fastAppTargetType; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setData(String data) { |
| | | this.data = data; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setNotification(AndroidNotification notification) { |
| | | this.notification = notification; |
| | | return this; |
| | | } |
| | | |
| | | public AndroidConfig build() { |
| | | return new AndroidConfig(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.apns.ApnsHeaders; |
| | | import com.huawei.push.apns.ApnsHmsOptions; |
| | | import com.huawei.push.apns.Aps; |
| | | import com.huawei.push.util.CollectionUtils; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | public class ApnsConfig { |
| | | @JSONField(name = "hms_options") |
| | | private ApnsHmsOptions hmsOptions; |
| | | |
| | | @JSONField(name = "headers") |
| | | private ApnsHeaders apnsHeaders; |
| | | |
| | | @JSONField(name = "payload") |
| | | private Map<String, Object> payload = new HashMap<>(); |
| | | |
| | | public void check() { |
| | | if (this.hmsOptions != null) { |
| | | this.hmsOptions.check(); |
| | | } |
| | | if (this.apnsHeaders != null) { |
| | | this.apnsHeaders.check(); |
| | | } |
| | | if (this.payload != null) { |
| | | if (this.payload.get("aps") != null) { |
| | | Aps aps = (Aps) this.payload.get("aps"); |
| | | aps.check(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public ApnsConfig(Builder builder) { |
| | | this.hmsOptions = builder.hmsOptions; |
| | | this.apnsHeaders = builder.apnsHeaders; |
| | | if (!CollectionUtils.isEmpty(builder.payload) || builder.aps != null) { |
| | | if (!CollectionUtils.isEmpty(builder.payload)) { |
| | | this.payload.putAll(builder.payload); |
| | | } |
| | | if (builder.aps != null) { |
| | | this.payload.put("aps", builder.aps); |
| | | } |
| | | } else { |
| | | this.payload = null; |
| | | } |
| | | } |
| | | |
| | | public ApnsHmsOptions getHmsOptions() { |
| | | return hmsOptions; |
| | | } |
| | | |
| | | public Map<String, Object> getPayload() { |
| | | return payload; |
| | | } |
| | | |
| | | public ApnsHeaders getApnsHeaders() { |
| | | return apnsHeaders; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private ApnsHmsOptions hmsOptions; |
| | | private Map<String, Object> payload = new HashMap<>(); |
| | | private ApnsHeaders apnsHeaders; |
| | | private Aps aps; |
| | | |
| | | public Builder setHmsOptions(ApnsHmsOptions hmsOptions) { |
| | | this.hmsOptions = hmsOptions; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addPayload(String key, Object value) { |
| | | this.payload.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllPayload(Map<String, Object> map) { |
| | | this.payload.putAll(map); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApnsHeaders(ApnsHeaders apnsHeaders) { |
| | | this.apnsHeaders = apnsHeaders; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addPayloadAps(Aps aps) { |
| | | this.aps = aps; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addPayload(Aps aps) { |
| | | this.aps = aps; |
| | | return this; |
| | | } |
| | | |
| | | public ApnsConfig build() { |
| | | return new ApnsConfig(this); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.google.common.base.Strings; |
| | | import com.google.common.primitives.Booleans; |
| | | import com.huawei.push.util.CollectionUtils; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | public class Message { |
| | | @JSONField(name = "data") |
| | | private String data; |
| | | |
| | | @JSONField(name = "notification") |
| | | private Notification notification; |
| | | |
| | | @JSONField(name = "android") |
| | | private AndroidConfig androidConfig; |
| | | |
| | | @JSONField(name = "apns") |
| | | private ApnsConfig apns; |
| | | |
| | | @JSONField(name = "webpush") |
| | | private WebPushConfig webpush; |
| | | |
| | | @JSONField(name = "token") |
| | | private List<String> token = new ArrayList<>(); |
| | | |
| | | @JSONField(name = "topic") |
| | | private String topic; |
| | | |
| | | @JSONField(name = "condition") |
| | | private String condition; |
| | | |
| | | private Message(Builder builder) { |
| | | this.data = builder.data; |
| | | this.notification = builder.notification; |
| | | this.androidConfig = builder.androidConfig; |
| | | this.apns = builder.apns; |
| | | this.webpush = builder.webpush; |
| | | |
| | | if (!CollectionUtils.isEmpty(builder.token)) { |
| | | this.token.addAll(builder.token); |
| | | } else { |
| | | this.token = null; |
| | | } |
| | | |
| | | this.topic = builder.topic; |
| | | this.condition = builder.condition; |
| | | |
| | | /** check after message is created */ |
| | | check(); |
| | | } |
| | | |
| | | /** |
| | | * check message's parameters |
| | | */ |
| | | public void check() { |
| | | |
| | | int count = Booleans.countTrue( |
| | | !CollectionUtils.isEmpty(this.token), |
| | | !Strings.isNullOrEmpty(this.topic), |
| | | !Strings.isNullOrEmpty(this.condition) |
| | | ); |
| | | |
| | | ValidatorUtils.checkArgument(count == 1, "Exactly one of token, topic or condition must be specified"); |
| | | |
| | | boolean isEmptyData = StringUtils.isEmpty(data); |
| | | |
| | | if (this.notification != null) { |
| | | this.notification.check(); |
| | | } |
| | | |
| | | if (null != this.androidConfig) { |
| | | this.androidConfig.check(this.notification); |
| | | } |
| | | |
| | | if (this.apns != null) { |
| | | this.apns.check(); |
| | | } |
| | | |
| | | if (this.webpush != null) { |
| | | this.webpush.check(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * getter |
| | | */ |
| | | public String getData() { |
| | | return data; |
| | | } |
| | | |
| | | public Notification getNotification() { |
| | | return notification; |
| | | } |
| | | |
| | | public AndroidConfig getAndroidConfig() { |
| | | return androidConfig; |
| | | } |
| | | |
| | | public ApnsConfig getApns() { |
| | | return apns; |
| | | } |
| | | |
| | | public WebPushConfig getWebpush() { |
| | | return webpush; |
| | | } |
| | | |
| | | public List<String> getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public String getTopic() { |
| | | return topic; |
| | | } |
| | | |
| | | public String getCondition() { |
| | | return condition; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | * |
| | | * @return |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | /** |
| | | * push message builder |
| | | */ |
| | | public static class Builder { |
| | | private String data; |
| | | private Notification notification; |
| | | private AndroidConfig androidConfig; |
| | | private ApnsConfig apns; |
| | | private WebPushConfig webpush; |
| | | private List<String> token = new ArrayList<>(); |
| | | private String topic; |
| | | private String condition; |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setData(String data) { |
| | | this.data = data; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setNotification(Notification notification) { |
| | | this.notification = notification; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAndroidConfig(AndroidConfig androidConfig) { |
| | | this.androidConfig = androidConfig; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setApns(ApnsConfig apns) { |
| | | this.apns = apns; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWebpush(WebPushConfig webpush) { |
| | | this.webpush = webpush; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addToken(String token) { |
| | | this.token.add(token); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllToken(List<String> tokens) { |
| | | this.token.addAll(tokens); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTopic(String topic) { |
| | | this.topic = topic; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setCondition(String condition) { |
| | | this.condition = condition; |
| | | return this; |
| | | } |
| | | |
| | | public Message build() { |
| | | return new Message(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import java.util.Locale; |
| | | |
| | | public class Notification { |
| | | @JSONField(name = "title") |
| | | private String title; |
| | | |
| | | @JSONField(name = "body") |
| | | private String body; |
| | | |
| | | @JSONField(name = "image") |
| | | private String image; |
| | | |
| | | public Notification() { |
| | | } |
| | | |
| | | public Notification(String title, String body) { |
| | | this.title = title; |
| | | this.body = body; |
| | | } |
| | | |
| | | public Notification(String title, String body, String image) { |
| | | this.title = title; |
| | | this.body = body; |
| | | this.image = image; |
| | | } |
| | | |
| | | public Notification(Builder builder) { |
| | | this.title = builder.title; |
| | | this.body = builder.body; |
| | | this.image = builder.image; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.image != null) { |
| | | ValidatorUtils.checkArgument(this.image.toLowerCase(Locale.getDefault()).trim().startsWith("https"), "image's url should start with HTTPS"); |
| | | } |
| | | } |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public void setTitle(String title) { |
| | | this.title = title; |
| | | } |
| | | |
| | | public String getBody() { |
| | | return body; |
| | | } |
| | | |
| | | public void setBody(String body) { |
| | | this.body = body; |
| | | } |
| | | |
| | | public String getImage() { |
| | | return image; |
| | | } |
| | | |
| | | public void setImage(String image) { |
| | | this.image = image; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | * |
| | | * @return |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | /** |
| | | * push message builder |
| | | */ |
| | | public static class Builder { |
| | | private String title; |
| | | |
| | | private String body; |
| | | |
| | | private String image; |
| | | |
| | | public Builder setTitle(String title) { |
| | | this.title = title; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBody(String body) { |
| | | this.body = body; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setImage(String image) { |
| | | this.image = image; |
| | | return this; |
| | | } |
| | | |
| | | public Notification build() { |
| | | return new Notification(this); |
| | | } |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | |
| | | public class TokenMessage { |
| | | @JSONField(name = "token") |
| | | private String token; |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public TokenMessage(Builder builder){ |
| | | this.token = builder.token; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | * |
| | | * @return |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String token; |
| | | |
| | | public Builder setToken(String token) { |
| | | this.token = token; |
| | | return this; |
| | | } |
| | | |
| | | public TokenMessage build(){ |
| | | return new TokenMessage(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.CollectionUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | public class TopicMessage { |
| | | @JSONField(name = "topic") |
| | | private String topic; |
| | | |
| | | @JSONField(name = "tokenArray") |
| | | private List<String> tokenArray = new ArrayList<String>(); |
| | | |
| | | @JSONField(name = "token") |
| | | private String token; |
| | | |
| | | public String getTopic() { |
| | | return topic; |
| | | } |
| | | |
| | | public List<String> getTokenArray() { |
| | | return tokenArray; |
| | | } |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | private TopicMessage(Builder builder) { |
| | | this.topic = builder.topic; |
| | | if (!CollectionUtils.isEmpty(builder.tokenArray)) { |
| | | this.tokenArray.addAll(builder.tokenArray); |
| | | } else { |
| | | this.tokenArray = null; |
| | | } |
| | | this.token = builder.token; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | * |
| | | * @return |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String topic; |
| | | private List<String> tokenArray = new ArrayList<String>(); |
| | | private String token; |
| | | |
| | | public Builder setTopic(String topic) { |
| | | this.topic = topic; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addToken(String token) { |
| | | this.tokenArray.add(token); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllToken(List<String> tokenArray) { |
| | | this.tokenArray.addAll(tokenArray); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setToken(String token) { |
| | | this.token = token; |
| | | return this; |
| | | } |
| | | |
| | | public TopicMessage build() { |
| | | return new TopicMessage(this); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.message; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.webpush.WebHmsOptions; |
| | | import com.huawei.push.webpush.WebNotification; |
| | | import com.huawei.push.webpush.WebpushHeaders; |
| | | |
| | | public class WebPushConfig { |
| | | @JSONField(name = "headers") |
| | | private WebpushHeaders headers; |
| | | |
| | | @JSONField(name = "data") |
| | | private String data; |
| | | |
| | | @JSONField(name = "notification") |
| | | private WebNotification notification; |
| | | |
| | | @JSONField(name = "hms_options") |
| | | private WebHmsOptions webHmsOptions; |
| | | |
| | | public WebpushHeaders getHeaders() { |
| | | return headers; |
| | | } |
| | | |
| | | public String getData() { |
| | | return data; |
| | | } |
| | | |
| | | public WebNotification getNotification() { |
| | | return notification; |
| | | } |
| | | |
| | | public WebHmsOptions getWebHmsOptions() { |
| | | return webHmsOptions; |
| | | } |
| | | |
| | | public WebPushConfig(Builder builder) { |
| | | this.headers = builder.headers; |
| | | this.data = builder.data; |
| | | this.notification = builder.notification; |
| | | this.webHmsOptions = builder.webHmsOptions; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.headers != null) { |
| | | this.headers.check(); |
| | | } |
| | | if (this.notification != null) { |
| | | this.notification.check(); |
| | | } |
| | | if (this.webHmsOptions != null) { |
| | | this.webHmsOptions.check(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private WebpushHeaders headers; |
| | | |
| | | private String data; |
| | | |
| | | private WebNotification notification; |
| | | |
| | | private WebHmsOptions webHmsOptions; |
| | | |
| | | public Builder setHeaders(WebpushHeaders headers) { |
| | | this.headers = headers; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setData(String data) { |
| | | this.data = data; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setNotification(WebNotification notification) { |
| | | this.notification = notification; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setWebHmsOptions(WebHmsOptions webHmsOptions) { |
| | | this.webHmsOptions = webHmsOptions; |
| | | return this; |
| | | } |
| | | |
| | | public WebPushConfig build() { |
| | | return new WebPushConfig(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* Copyright 2017 Google Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | |
| | | * 2019.12.15-Changed constructor HuaweiApp |
| | | * 2019.12.15-Changed method initializeApp |
| | | * Huawei Technologies Co., Ltd. |
| | | * |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.google.common.collect.ImmutableList; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.io.IOException; |
| | | import java.text.MessageFormat; |
| | | import java.util.*; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.ScheduledFuture; |
| | | import java.util.concurrent.ThreadFactory; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | |
| | | /** |
| | | * The entry point of Huawei Java SDK. |
| | | * <p>{@link HuaweiApp#initializeApp(HuaweiOption)} initializes the app instance. |
| | | */ |
| | | public class HuaweiApp { |
| | | private static final Logger logger = LoggerFactory.getLogger(HuaweiApp.class); |
| | | |
| | | private String appId; |
| | | private HuaweiOption option; |
| | | |
| | | /** Global lock */ |
| | | private static final Object appsLock = new Object(); |
| | | |
| | | /** Store a map of <appId, HuaweiApp> */ |
| | | private static final Map<String, HuaweiApp> instances = new HashMap<>(); |
| | | |
| | | /** HuaweiMessaging can be added in the pattern of service, whcih is designed for Scalability */ |
| | | private final Map<String, HuaweiService> services = new HashMap<>(); |
| | | |
| | | private TokenRefresher tokenRefresher; |
| | | |
| | | private volatile ScheduledExecutorService scheduledExecutor; |
| | | |
| | | private ThreadManager threadManager; |
| | | |
| | | private ThreadManager.HuaweiExecutors executors; |
| | | |
| | | private final AtomicBoolean deleted = new AtomicBoolean(); |
| | | |
| | | /** lock for synchronizing all internal HuaweiApp state changes */ |
| | | private final Object lock = new Object(); |
| | | |
| | | private HuaweiApp(HuaweiOption option) { |
| | | ValidatorUtils.checkArgument(option != null, "HuaweiOption must not be null"); |
| | | this.option = option; |
| | | this.appId = option.getCredential().getAppId(); |
| | | this.tokenRefresher = new TokenRefresher(this); |
| | | this.threadManager = option.getThreadManager(); |
| | | this.executors = threadManager.getHuaweiExecutors(this); |
| | | } |
| | | |
| | | public HuaweiOption getOption() { |
| | | return option; |
| | | } |
| | | |
| | | public String getAppId() { |
| | | return appId; |
| | | } |
| | | |
| | | /** |
| | | * Returns the instance identified by the unique appId, or throws if it does not exist. |
| | | * |
| | | * @param appId represents the id of the {@link HuaweiApp} instance. |
| | | * @return the {@link HuaweiApp} corresponding to the id. |
| | | * @throws IllegalStateException if the {@link HuaweiApp} was not initialized, either via {@link |
| | | * #initializeApp(HuaweiOption)} or {@link #getApps()}. |
| | | */ |
| | | public static HuaweiApp getInstance(HuaweiOption option) { |
| | | String appId = option.getCredential().getAppId(); |
| | | synchronized (appsLock) { |
| | | HuaweiApp app = instances.get(appId); |
| | | if (app != null) { |
| | | return app; |
| | | } |
| | | // String errorMessage = MessageFormat.format("HuaweiApp with id {0} doesn't exist", appId); |
| | | // throw new IllegalStateException(errorMessage); |
| | | return initializeApp(option); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Initializes the {@link HuaweiApp} instance using the given option. |
| | | * |
| | | * @throws IllegalStateException if the app instance has already been initialized. |
| | | */ |
| | | public static HuaweiApp initializeApp(HuaweiOption option) { |
| | | String appId = option.getCredential().getAppId(); |
| | | final HuaweiApp app; |
| | | synchronized (appsLock) { |
| | | if (!instances.containsKey(appId)) { |
| | | ValidatorUtils.checkState(!instances.containsKey(appId), "HuaweiApp with id " + appId + " already exists!"); |
| | | app = new HuaweiApp(option); |
| | | instances.put(appId, app); |
| | | app.startTokenRefresher(); |
| | | } else { |
| | | app = getInstance(option); |
| | | } |
| | | |
| | | } |
| | | return app; |
| | | } |
| | | |
| | | /** Returns a list of all HuaweiApps. */ |
| | | public static List<HuaweiApp> getApps() { |
| | | synchronized (appsLock) { |
| | | return ImmutableList.copyOf(instances.values()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Get all appIds which are be stored in the instances |
| | | */ |
| | | public static List<String> getAllAppIds() { |
| | | Set<String> allAppIds = new HashSet<>(); |
| | | synchronized (appsLock) { |
| | | for (HuaweiApp app : instances.values()) { |
| | | allAppIds.add(app.getAppId()); |
| | | } |
| | | } |
| | | List<String> sortedIdList = new ArrayList<>(allAppIds); |
| | | Collections.sort(sortedIdList); |
| | | return sortedIdList; |
| | | } |
| | | |
| | | /** |
| | | * Deletes the {@link HuaweiApp} and all its data. All calls to this {@link HuaweiApp} |
| | | * instance will throw once it has been called. |
| | | * |
| | | * <p>A no-op if delete was called before. |
| | | */ |
| | | public void delete() { |
| | | synchronized (lock) { |
| | | boolean valueChanged = deleted.compareAndSet(false /* expected */, true); |
| | | if (!valueChanged) { |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | this.getOption().getHttpClient().close(); |
| | | this.getOption().getCredential().getHttpClient().close(); |
| | | } catch (IOException e) { |
| | | logger.debug("Fail to close httpClient"); |
| | | } |
| | | |
| | | for (HuaweiService service : services.values()) { |
| | | service.destroy(); |
| | | } |
| | | services.clear(); |
| | | tokenRefresher.stop(); |
| | | |
| | | threadManager.releaseHuaweiExecutors(this, executors); |
| | | if (scheduledExecutor != null) { |
| | | scheduledExecutor.shutdown(); |
| | | scheduledExecutor = null; |
| | | } |
| | | } |
| | | |
| | | synchronized (appsLock) { |
| | | instances.remove(this.getAppId()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Check the app is not deleted, whcic is the premisi of some methods |
| | | */ |
| | | private void checkNotDeleted() { |
| | | String errorMessage = MessageFormat.format("HuaweiApp with id {0} was deleted", getAppId()); |
| | | ValidatorUtils.checkState(!deleted.get(), errorMessage); |
| | | } |
| | | |
| | | /** |
| | | * Singleton mode, ensure the scheduleExecutor is singleton |
| | | */ |
| | | private ScheduledExecutorService singleScheduledExecutorService() { |
| | | if (scheduledExecutor == null) { |
| | | synchronized (lock) { |
| | | checkNotDeleted(); |
| | | if (scheduledExecutor == null) { |
| | | scheduledExecutor = new HuaweiScheduledExecutor(getThreadFactory(), "huawei-scheduled-worker"); |
| | | } |
| | | } |
| | | } |
| | | return scheduledExecutor; |
| | | } |
| | | |
| | | public ThreadFactory getThreadFactory() { |
| | | return threadManager.getThreadFactory(); |
| | | } |
| | | |
| | | private ScheduledExecutorService getScheduledExecutorService() { |
| | | return singleScheduledExecutorService(); |
| | | } |
| | | |
| | | ScheduledFuture<?> schedule(Runnable runnable, long initialDelay, long period) { |
| | | return getScheduledExecutorService().scheduleWithFixedDelay(runnable, initialDelay, period, TimeUnit.MILLISECONDS); |
| | | } |
| | | |
| | | /** |
| | | * Add service to the app, such as HuaweiMessaging, other services can be added if needed |
| | | */ |
| | | void addService(HuaweiService service) { |
| | | synchronized (lock) { |
| | | checkNotDeleted(); |
| | | ValidatorUtils.checkArgument(!services.containsKey(service.getId()), "service already exists"); |
| | | services.put(service.getId(), service); |
| | | } |
| | | } |
| | | |
| | | HuaweiService getService(String id) { |
| | | synchronized (lock) { |
| | | return services.get(id); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Start the scheduled task for refreshing token automatically |
| | | */ |
| | | public void startTokenRefresher() { |
| | | synchronized (lock) { |
| | | checkNotDeleted(); |
| | | tokenRefresher.start(); |
| | | } |
| | | } |
| | | |
| | | /** It is just for test */ |
| | | public static void clearInstancesForTest() { |
| | | synchronized (appsLock) { |
| | | //copy before delete |
| | | for (HuaweiApp app : ImmutableList.copyOf(instances.values())) { |
| | | app.delete(); |
| | | } |
| | | instances.clear(); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | |
| | | import org.apache.http.client.methods.CloseableHttpResponse; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.io.IOException; |
| | | import java.text.MessageFormat; |
| | | import java.util.ResourceBundle; |
| | | import java.util.concurrent.locks.Lock; |
| | | import java.util.concurrent.locks.ReentrantLock; |
| | | |
| | | /** |
| | | * Accept the appId and appSecret given by the user and build the credential |
| | | * Every app has a credential which is for certification |
| | | */ |
| | | public class HuaweiCredential { |
| | | private static final Logger logger = LoggerFactory.getLogger(HuaweiCredential.class); |
| | | |
| | | private final String PUSH_AT_URL = ResourceBundle.getBundle("hw_push_url").getString("token_server"); |
| | | |
| | | private String appId; |
| | | private String appSecret; |
| | | |
| | | private String accessToken; |
| | | private long expireIn; |
| | | private Lock lock; |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | private HuaweiCredential(Builder builder) { |
| | | this.lock = new ReentrantLock(); |
| | | this.appId = builder.appId; |
| | | this.appSecret = builder.appSecret; |
| | | if (builder.httpClient == null) { |
| | | httpClient = HttpClients.createDefault(); |
| | | } else { |
| | | this.httpClient = builder.httpClient; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Refresh accessToken via HCM manually. |
| | | */ |
| | | public final void refreshToken() { |
| | | try { |
| | | executeRefresh(); |
| | | } catch (IOException e) { |
| | | logger.debug("Fail to refresh token!", e); |
| | | } |
| | | } |
| | | |
| | | private void executeRefresh() throws IOException { |
| | | String requestBody = createRequestBody(appId, appSecret); |
| | | |
| | | HttpPost httpPost = new HttpPost(PUSH_AT_URL); |
| | | StringEntity entity = new StringEntity(requestBody); |
| | | httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); |
| | | httpPost.setEntity(entity); |
| | | CloseableHttpResponse response = httpClient.execute(httpPost); |
| | | String jsonStr = EntityUtils.toString(response.getEntity()); |
| | | int statusCode = response.getStatusLine().getStatusCode(); |
| | | if (statusCode == 200) { |
| | | JSONObject jsonObject = JSONObject.parseObject(jsonStr); |
| | | this.accessToken = jsonObject.getString("access_token"); |
| | | this.expireIn = jsonObject.getLong("expires_in") * 1000L; |
| | | } else { |
| | | logger.debug("Fail to refresh token!"); |
| | | } |
| | | } |
| | | |
| | | private String createRequestBody(String appId, String appSecret) { |
| | | return MessageFormat.format("grant_type=client_credentials&client_secret={0}&client_id={1}", appSecret, appId); |
| | | } |
| | | |
| | | /** |
| | | * getter |
| | | */ |
| | | public final String getAccessToken() { |
| | | this.lock.lock(); |
| | | |
| | | String tmp; |
| | | try { |
| | | tmp = this.accessToken; |
| | | } finally { |
| | | this.lock.unlock(); |
| | | } |
| | | |
| | | return tmp; |
| | | } |
| | | |
| | | public final long getExpireIn() { |
| | | this.lock.lock(); |
| | | |
| | | long tmp; |
| | | try { |
| | | tmp = this.expireIn; |
| | | } finally { |
| | | this.lock.unlock(); |
| | | } |
| | | |
| | | return tmp; |
| | | } |
| | | |
| | | protected CloseableHttpClient getHttpClient() { |
| | | return httpClient; |
| | | } |
| | | |
| | | public String getAppId() { |
| | | return appId; |
| | | } |
| | | |
| | | /** |
| | | * Builder for constructing {@link HuaweiCredential}. |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String appId; |
| | | private String appSecret; |
| | | |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setAppId(String appId) { |
| | | this.appId = appId; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setAppSecret(String appSecret) { |
| | | this.appSecret = appSecret; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setHttpClient(CloseableHttpClient httpClient) { |
| | | this.httpClient = httpClient; |
| | | return this; |
| | | } |
| | | |
| | | public HuaweiCredential build() { |
| | | return new HuaweiCredential(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.huawei.push.exception.HuaweiMesssagingException; |
| | | import com.huawei.push.message.Message; |
| | | import com.huawei.push.message.TopicMessage; |
| | | import com.huawei.push.reponse.SendResponse; |
| | | |
| | | /** |
| | | * sending messages interface |
| | | */ |
| | | public interface HuaweiMessageClient { |
| | | |
| | | /** |
| | | * Sends the given message with HCM. |
| | | * |
| | | * @param message message {@link Message} |
| | | * @param validateOnly A boolean indicating whether to send message for test. or not. |
| | | * @return {@link SendResponse}. |
| | | * @throws HuaweiMesssagingException |
| | | */ |
| | | SendResponse send(Message message, boolean validateOnly, String accessToken) throws HuaweiMesssagingException; |
| | | |
| | | SendResponse send(TopicMessage message, String operation, String accessToken) throws HuaweiMesssagingException; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.huawei.push.exception.HuaweiMesssagingException; |
| | | import com.huawei.push.message.Message; |
| | | import com.huawei.push.message.TopicMessage; |
| | | import com.huawei.push.model.TopicOperation; |
| | | import com.huawei.push.reponse.SendResponse; |
| | | import com.huawei.push.reponse.TopicListResponse; |
| | | import com.huawei.push.reponse.TopicSendResponse; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.http.client.HttpResponseException; |
| | | import org.apache.http.client.methods.CloseableHttpResponse; |
| | | import org.apache.http.client.methods.HttpPost; |
| | | import org.apache.http.entity.StringEntity; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.util.EntityUtils; |
| | | |
| | | import java.io.IOException; |
| | | import java.text.MessageFormat; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.ResourceBundle; |
| | | |
| | | public class HuaweiMessageClientImpl implements HuaweiMessageClient { |
| | | private static final String PUSH_URL = ResourceBundle.getBundle("hw_push_url").getString("push_open_url"); |
| | | |
| | | private final String HcmPushUrl; |
| | | private String hcmTopicUrl; |
| | | private String hcmGroupUrl; |
| | | private String hcmTokenUrl; |
| | | private final CloseableHttpClient httpClient; |
| | | |
| | | private HuaweiMessageClientImpl(Builder builder) { |
| | | this.HcmPushUrl = MessageFormat.format(PUSH_URL + "/v1/{0}/messages:send", builder.appId); |
| | | this.hcmTopicUrl = MessageFormat.format(PUSH_URL + "/v1/{0}/topic:{1}", builder.appId); |
| | | |
| | | ValidatorUtils.checkArgument(builder.httpClient != null, "requestFactory must not be null"); |
| | | this.httpClient = builder.httpClient; |
| | | } |
| | | |
| | | /** |
| | | * getter |
| | | */ |
| | | public String getHcmSendUrl() { |
| | | return HcmPushUrl; |
| | | } |
| | | |
| | | public CloseableHttpClient getHttpClient() { |
| | | return httpClient; |
| | | } |
| | | |
| | | @Override |
| | | public SendResponse send(Message message, boolean validateOnly, String accessToken) throws HuaweiMesssagingException { |
| | | try { |
| | | return sendRequest(message, validateOnly, accessToken); |
| | | } catch (IOException e) { |
| | | throw new HuaweiMesssagingException(HuaweiMessaging.INTERNAL_ERROR, "Error while calling HCM backend service", e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public SendResponse send(TopicMessage message, String operation, String accessToken) throws HuaweiMesssagingException { |
| | | try { |
| | | return sendRequest(message, operation, accessToken); |
| | | } catch (IOException e) { |
| | | throw new HuaweiMesssagingException(HuaweiMessaging.INTERNAL_ERROR, "Error while calling HCM backend service", e); |
| | | } |
| | | } |
| | | |
| | | private SendResponse sendRequest(TopicMessage message, String operation, String accessToken) throws IOException, HuaweiMesssagingException { |
| | | this.hcmTopicUrl = MessageFormat.format(hcmTopicUrl, "", operation); |
| | | HttpPost httpPost = new HttpPost(this.hcmTopicUrl); |
| | | StringEntity entity = new StringEntity(JSON.toJSONString(message), "UTF-8"); |
| | | httpPost.setHeader("Authorization", "Bearer " + accessToken); |
| | | httpPost.setHeader("Content-Type", "application/json;charset=utf-8"); |
| | | httpPost.setEntity(entity); |
| | | CloseableHttpResponse response = httpClient.execute(httpPost); |
| | | String rpsContent = EntityUtils.toString(response.getEntity()); |
| | | int statusCode = response.getStatusLine().getStatusCode(); |
| | | if (statusCode == 200) { |
| | | JSONObject jsonObject = JSONObject.parseObject(rpsContent); |
| | | String code = jsonObject.getString("code"); |
| | | String msg = jsonObject.getString("msg"); |
| | | String requestId = jsonObject.getString("requestId"); |
| | | if (StringUtils.equals(code, "80000000")) { |
| | | SendResponse sendResponse; |
| | | if (StringUtils.equals(operation, TopicOperation.LIST.getValue())) { |
| | | JSONArray topics = jsonObject.getJSONArray("topics"); |
| | | sendResponse = TopicListResponse.fromCode(code, msg, requestId, topics); |
| | | } else { |
| | | Integer failureCount = jsonObject.getInteger("failureCount"); |
| | | Integer successCount = jsonObject.getInteger("successCount"); |
| | | JSONArray errors = jsonObject.getJSONArray("errors"); |
| | | sendResponse = TopicSendResponse.fromCode(code, msg, requestId, failureCount, successCount, errors); |
| | | } |
| | | return sendResponse; |
| | | } else { |
| | | String errorMsg = MessageFormat.format("error code : {0}, error message : {1}", String.valueOf(code), msg); |
| | | throw new HuaweiMesssagingException(HuaweiMessaging.KNOWN_ERROR, errorMsg); |
| | | } |
| | | } |
| | | HttpResponseException exception = new HttpResponseException(statusCode, rpsContent); |
| | | throw createExceptionFromResponse(exception); |
| | | } |
| | | |
| | | /** |
| | | * send request |
| | | * |
| | | * @param message message {@link Message} |
| | | * @param validateOnly A boolean indicating whether to send message for test or not. |
| | | * @param accessToken A String for oauth |
| | | * @return {@link SendResponse} |
| | | * @throws IOException If a error occurs when sending request |
| | | */ |
| | | private SendResponse sendRequest(Message message, boolean validateOnly, String accessToken) throws IOException, HuaweiMesssagingException { |
| | | Map<String, Object> map = createRequestMap(message, validateOnly); |
| | | HttpPost httpPost = new HttpPost(this.HcmPushUrl); |
| | | StringEntity entity = new StringEntity(JSON.toJSONString(map), "UTF-8"); |
| | | // String aqa = JSON.toJSONString(map); |
| | | httpPost.setHeader("Authorization", "Bearer " + accessToken); |
| | | httpPost.setHeader("Content-Type", "application/json;charset=utf-8"); |
| | | httpPost.setEntity(entity); |
| | | CloseableHttpResponse response = httpClient.execute(httpPost); |
| | | String rpsContent = EntityUtils.toString(response.getEntity()); |
| | | int statusCode = response.getStatusLine().getStatusCode(); |
| | | if (statusCode == 200) { |
| | | JSONObject jsonObject = JSONObject.parseObject(rpsContent); |
| | | String code = jsonObject.getString("code"); |
| | | String msg = jsonObject.getString("msg"); |
| | | String requestId = jsonObject.getString("requestId"); |
| | | if (StringUtils.equals(code, "80000000")) { |
| | | return SendResponse.fromCode(code, msg, requestId); |
| | | } else { |
| | | String errorMsg = MessageFormat.format("error code : {0}, error message : {1}", String.valueOf(code), msg); |
| | | throw new HuaweiMesssagingException(HuaweiMessaging.KNOWN_ERROR, errorMsg); |
| | | } |
| | | } |
| | | HttpResponseException exception = new HttpResponseException(statusCode, rpsContent); |
| | | throw createExceptionFromResponse(exception); |
| | | } |
| | | |
| | | /** |
| | | * create the map of the request body, mostly for wrapping the message with validate_only |
| | | * |
| | | * @param message A non-null {@link Message} to be sent. |
| | | * @param validateOnly A boolean indicating whether to send message for test or not. |
| | | * @return a map of request |
| | | */ |
| | | private Map<String, Object> createRequestMap(Message message, boolean validateOnly) { |
| | | return new HashMap<String, Object>() { |
| | | { |
| | | put("validate_only", validateOnly); |
| | | put("message", message); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | private HuaweiMesssagingException createExceptionFromResponse(HttpResponseException e) { |
| | | String msg = MessageFormat.format("Unexpected HTTP response with status : {0}, body : {1}", e.getStatusCode(), e.getMessage()); |
| | | return new HuaweiMesssagingException(HuaweiMessaging.UNKNOWN_ERROR, msg, e); |
| | | } |
| | | |
| | | static HuaweiMessageClientImpl fromApp(HuaweiApp app) { |
| | | String appId = ImplHuaweiTrampolines.getAppId(app); |
| | | return HuaweiMessageClientImpl.builder() |
| | | .setAppId(appId) |
| | | .setHttpClient(app.getOption().getHttpClient()) |
| | | .build(); |
| | | } |
| | | |
| | | static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | static final class Builder { |
| | | |
| | | private String appId; |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setAppId(String appId) { |
| | | this.appId = appId; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setHttpClient(CloseableHttpClient httpClient) { |
| | | this.httpClient = httpClient; |
| | | return this; |
| | | } |
| | | |
| | | public HuaweiMessageClientImpl build() { |
| | | return new HuaweiMessageClientImpl(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.google.common.base.Supplier; |
| | | import com.google.common.base.Suppliers; |
| | | import com.huawei.push.exception.HuaweiMesssagingException; |
| | | import com.huawei.push.message.Message; |
| | | import com.huawei.push.message.TopicMessage; |
| | | import com.huawei.push.model.TopicOperation; |
| | | import com.huawei.push.reponse.SendResponse; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | /** |
| | | * This class is the entrance for all server-side HCM actions. |
| | | * |
| | | * <p>You can get a instance of {@link com.huawei.push.messaging.HuaweiMessaging} |
| | | * by a instance of {@link com.huawei.push.messaging.HuaweiApp}, and then use it to send a message |
| | | */ |
| | | public class HuaweiMessaging { |
| | | private static final Logger logger = LoggerFactory.getLogger(HuaweiMessaging.class); |
| | | |
| | | static final String INTERNAL_ERROR = "internal error"; |
| | | |
| | | static final String UNKNOWN_ERROR = "unknown error"; |
| | | |
| | | static final String KNOWN_ERROR = "known error"; |
| | | |
| | | private final HuaweiApp app; |
| | | private final Supplier<? extends HuaweiMessageClient> messagingClient; |
| | | |
| | | private HuaweiMessaging(Builder builder) { |
| | | this.app = builder.app; |
| | | this.messagingClient = Suppliers.memoize(builder.messagingClient); |
| | | } |
| | | |
| | | /** |
| | | * Gets the {@link HuaweiMessaging} instance for the specified {@link HuaweiApp}. |
| | | * |
| | | * @return The {@link HuaweiMessaging} instance for the specified {@link HuaweiApp}. |
| | | */ |
| | | public static synchronized HuaweiMessaging getInstance(HuaweiApp app) { |
| | | HuaweiMessagingService service = ImplHuaweiTrampolines.getService(app, SERVICE_ID, HuaweiMessagingService.class); |
| | | if (service == null) { |
| | | service = ImplHuaweiTrampolines.addService(app, new HuaweiMessagingService(app)); |
| | | } |
| | | return service.getInstance(); |
| | | } |
| | | |
| | | private static HuaweiMessaging fromApp(final HuaweiApp app) { |
| | | return HuaweiMessaging.builder() |
| | | .setApp(app) |
| | | .setMessagingClient(() -> HuaweiMessageClientImpl.fromApp(app)) |
| | | .build(); |
| | | } |
| | | |
| | | HuaweiMessageClient getMessagingClient() { |
| | | return messagingClient.get(); |
| | | } |
| | | |
| | | /** |
| | | * Sends the given {@link Message} via HCM. |
| | | * |
| | | * @param message A non-null {@link Message} to be sent. |
| | | * @return {@link SendResponse}. |
| | | * @throws HuaweiMesssagingException If an error occurs while handing the message off to HCM for |
| | | * delivery. |
| | | */ |
| | | public SendResponse sendMessage(Message message) throws HuaweiMesssagingException { |
| | | return sendMessage(message, false); |
| | | } |
| | | |
| | | /** |
| | | * @param topicMessage topicmessage |
| | | * @return topic subscribe response |
| | | * @throws HuaweiMesssagingException |
| | | */ |
| | | public SendResponse subscribeTopic(TopicMessage topicMessage) throws HuaweiMesssagingException { |
| | | final HuaweiMessageClient messagingClient = getMessagingClient(); |
| | | return messagingClient.send(topicMessage, TopicOperation.SUBSCRIBE.getValue(), ImplHuaweiTrampolines.getAccessToken(app)); |
| | | } |
| | | |
| | | /** |
| | | * @param topicMessage topic Message |
| | | * @return topic unsubscribe response |
| | | * @throws HuaweiMesssagingException |
| | | */ |
| | | public SendResponse unsubscribeTopic(TopicMessage topicMessage) throws HuaweiMesssagingException { |
| | | final HuaweiMessageClient messagingClient = getMessagingClient(); |
| | | return messagingClient.send(topicMessage, TopicOperation.UNSUBSCRIBE.getValue(), ImplHuaweiTrampolines.getAccessToken(app)); |
| | | } |
| | | |
| | | /** |
| | | * @param topicMessage topic Message |
| | | * @return topic list |
| | | * @throws HuaweiMesssagingException |
| | | */ |
| | | public SendResponse listTopic(TopicMessage topicMessage) throws HuaweiMesssagingException { |
| | | final HuaweiMessageClient messagingClient = getMessagingClient(); |
| | | return messagingClient.send(topicMessage, TopicOperation.LIST.getValue(), ImplHuaweiTrampolines.getAccessToken(app)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Sends message {@link Message} |
| | | * |
| | | * <p>If the {@code validateOnly} option is set to true, the message will not be actually sent. Instead |
| | | * HCM performs all the necessary validations, and emulates the send operation. |
| | | * |
| | | * @param message message {@link Message} to be sent. |
| | | * @param validateOnly a boolean indicating whether to send message for test or not. |
| | | * @return {@link SendResponse}. |
| | | * @throws HuaweiMesssagingException exception. |
| | | */ |
| | | public SendResponse sendMessage(Message message, boolean validateOnly) throws HuaweiMesssagingException { |
| | | ValidatorUtils.checkArgument(message != null, "message must not be null"); |
| | | final HuaweiMessageClient messagingClient = getMessagingClient(); |
| | | return messagingClient.send(message, validateOnly, ImplHuaweiTrampolines.getAccessToken(app)); |
| | | } |
| | | |
| | | /** |
| | | * HuaweiMessagingService |
| | | */ |
| | | private static final String SERVICE_ID = HuaweiMessaging.class.getName(); |
| | | |
| | | private static class HuaweiMessagingService extends HuaweiService<HuaweiMessaging> { |
| | | |
| | | HuaweiMessagingService(HuaweiApp app) { |
| | | super(SERVICE_ID, HuaweiMessaging.fromApp(app)); |
| | | } |
| | | |
| | | @Override |
| | | public void destroy() { |
| | | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Builder for constructing {@link HuaweiMessaging}. |
| | | */ |
| | | static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | static class Builder { |
| | | private HuaweiApp app; |
| | | private Supplier<? extends HuaweiMessageClient> messagingClient; |
| | | |
| | | private Builder() { |
| | | } |
| | | |
| | | public Builder setApp(HuaweiApp app) { |
| | | this.app = app; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setMessagingClient(Supplier<? extends HuaweiMessageClient> messagingClient) { |
| | | this.messagingClient = messagingClient; |
| | | return this; |
| | | } |
| | | |
| | | public HuaweiMessaging build() { |
| | | return new HuaweiMessaging(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.huawei.push.util.IgnoreSSLUtils; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.security.KeyManagementException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | |
| | | /** Configurable HCM options. */ |
| | | public class HuaweiOption { |
| | | private static final Logger logger = LoggerFactory.getLogger(HuaweiOption.class); |
| | | |
| | | private final HuaweiCredential credential; |
| | | private final CloseableHttpClient httpClient; |
| | | private final ThreadManager threadManager; |
| | | |
| | | private HuaweiOption(HuaweiOption.Builder builder) { |
| | | ValidatorUtils.checkArgument(builder.credential != null, "HuaweiOption must be initialized with setCredential()"); |
| | | this.credential = builder.credential; |
| | | |
| | | ValidatorUtils.checkArgument(builder.httpClient != null, "HuaweiOption must be initialized with a non-null httpClient"); |
| | | this.httpClient = builder.httpClient; |
| | | |
| | | ValidatorUtils.checkArgument(builder.threadManager != null, "HuaweiOption must be initialized with a non-null threadManager"); |
| | | this.threadManager = builder.threadManager; |
| | | } |
| | | |
| | | /** |
| | | * Returns a instance of HuaweiCredential used for refreshing token. |
| | | * |
| | | * @return A <code>HuaweiCredential</code> instance. |
| | | */ |
| | | public HuaweiCredential getCredential() { |
| | | return credential; |
| | | } |
| | | |
| | | /** |
| | | * Returns a instance of httpclient used for sending http request. |
| | | * |
| | | * @return A <code>httpclient</code> instance. |
| | | */ |
| | | public CloseableHttpClient getHttpClient() { |
| | | return httpClient; |
| | | } |
| | | |
| | | public ThreadManager getThreadManager() { |
| | | return threadManager; |
| | | } |
| | | |
| | | /** |
| | | * Builder for constructing {@link HuaweiOption}. |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static final class Builder { |
| | | private HuaweiCredential credential; |
| | | private CloseableHttpClient httpClient; |
| | | |
| | | { |
| | | try { |
| | | httpClient = IgnoreSSLUtils.createClient(); |
| | | } catch (KeyManagementException | NoSuchAlgorithmException e) { |
| | | logger.debug("Fail to create httpClient for sending message", e); |
| | | } |
| | | } |
| | | |
| | | private ThreadManager threadManager = HuaweiThreadManager.DEFAULT_THREAD_MANAGER; |
| | | |
| | | |
| | | public Builder() {} |
| | | |
| | | public Builder setCredential(HuaweiCredential credential) { |
| | | this.credential = credential; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setHttpClient(CloseableHttpClient httpClient) { |
| | | this.httpClient = httpClient; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setThreadManager(ThreadManager threadManager) { |
| | | this.threadManager = threadManager; |
| | | return this; |
| | | } |
| | | |
| | | public HuaweiOption build() { |
| | | return new HuaweiOption(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* Copyright 2017 Google Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | |
| | | * 2019.12.15-Changed constructor HuaweiScheduledExecutor |
| | | * Huawei Technologies Co., Ltd. |
| | | * |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.google.common.base.Strings; |
| | | import com.google.common.util.concurrent.ThreadFactoryBuilder; |
| | | |
| | | import java.util.concurrent.ScheduledThreadPoolExecutor; |
| | | import java.util.concurrent.ThreadFactory; |
| | | |
| | | import static com.google.common.base.Preconditions.checkArgument; |
| | | |
| | | /** |
| | | * A single-threaded scheduled executor implementation. |
| | | */ |
| | | public class HuaweiScheduledExecutor extends ScheduledThreadPoolExecutor { |
| | | |
| | | public HuaweiScheduledExecutor(ThreadFactory threadFactory, String name) { |
| | | this(threadFactory, name, null); |
| | | } |
| | | |
| | | public HuaweiScheduledExecutor(ThreadFactory threadFactory, String name, Thread.UncaughtExceptionHandler handler) { |
| | | super(1, decorateThreadFactory(threadFactory, name, handler)); |
| | | setRemoveOnCancelPolicy(true); |
| | | } |
| | | |
| | | static ThreadFactory getThreadFactoryWithName(ThreadFactory threadFactory, String name) { |
| | | return decorateThreadFactory(threadFactory, name, null); |
| | | } |
| | | |
| | | private static ThreadFactory decorateThreadFactory( |
| | | ThreadFactory threadFactory, String name, Thread.UncaughtExceptionHandler handler) { |
| | | checkArgument(!Strings.isNullOrEmpty(name)); |
| | | ThreadFactoryBuilder builder = new ThreadFactoryBuilder() |
| | | .setThreadFactory(threadFactory) |
| | | .setNameFormat(name) |
| | | .setDaemon(true); |
| | | if (handler != null) { |
| | | builder.setUncaughtExceptionHandler(handler); |
| | | } |
| | | return builder.build(); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | /** |
| | | * the services exposed from the HCM SDK |
| | | * Each instance of the class is associated with one instance of the HuaweiApp |
| | | */ |
| | | public abstract class HuaweiService<T> { |
| | | private String id; |
| | | protected T instance; |
| | | |
| | | protected HuaweiService(String id, T instance) { |
| | | this.id = id; |
| | | this.instance = instance; |
| | | } |
| | | |
| | | public String getId() { |
| | | return id; |
| | | } |
| | | |
| | | public T getInstance() { |
| | | return instance; |
| | | } |
| | | |
| | | public abstract void destroy(); |
| | | } |
New file |
| | |
| | | /* Copyright 2017 Google Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | |
| | | * 2019.12.15-Changed method releaseExecutor |
| | | * Huawei Technologies Co., Ltd. |
| | | * |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import java.util.HashSet; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.ThreadFactory; |
| | | |
| | | |
| | | /** Default ThreadManager implementations used by the HCM SDK */ |
| | | public class HuaweiThreadManager { |
| | | |
| | | public static final ThreadManager DEFAULT_THREAD_MANAGER = new DefaultThreadManager(); |
| | | |
| | | /** |
| | | * An abstract ThreadManager implementation that uses the same executor service |
| | | * across all active apps. The executor service is initialized when the first app is initialized, |
| | | * and terminated when the last app is deleted. This class is thread safe. |
| | | */ |
| | | abstract static class GlobalThreadManager extends ThreadManager { |
| | | private final Object lock = new Object(); |
| | | private final Set<String> apps = new HashSet<>(); |
| | | private ExecutorService executorService; |
| | | |
| | | @Override |
| | | protected ExecutorService getExecutor(HuaweiApp app) { |
| | | synchronized (lock) { |
| | | if (executorService == null) { |
| | | executorService = doInit(); |
| | | } |
| | | apps.add(app.getOption().getCredential().getAppId()); |
| | | return executorService; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | protected void releaseExecutor(HuaweiApp app, ExecutorService executor) { |
| | | synchronized (lock) { |
| | | String appId = app.getOption().getCredential().getAppId(); |
| | | if (apps.remove(appId) && apps.isEmpty()) { |
| | | doCleanup(executorService); |
| | | executorService = null; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Initializes the executor service. Called when the first application is initialized. |
| | | */ |
| | | protected abstract ExecutorService doInit(); |
| | | |
| | | /** |
| | | * Cleans up the executor service. Called when the last application is deleted. |
| | | */ |
| | | protected abstract void doCleanup(ExecutorService executorService); |
| | | } |
| | | |
| | | private static class DefaultThreadManager extends GlobalThreadManager { |
| | | |
| | | @Override |
| | | protected ExecutorService doInit() { |
| | | ThreadFactory threadFactory = HuaweiScheduledExecutor.getThreadFactoryWithName(getThreadFactory(), "huawei-default-%d"); |
| | | return Executors.newCachedThreadPool(threadFactory); |
| | | } |
| | | |
| | | @Override |
| | | protected void doCleanup(ExecutorService executorService) { |
| | | executorService.shutdown(); |
| | | } |
| | | |
| | | @Override |
| | | protected ThreadFactory getThreadFactory() { |
| | | return Executors.defaultThreadFactory(); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* Copyright 2017 Google Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | |
| | | * 2019.12.15-added method getAccessToken |
| | | * Huawei Technologies Co., Ltd. |
| | | * |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import org.apache.http.client.HttpClient; |
| | | |
| | | /** |
| | | * Provides trampolines into package-private APIs used by components of HCM |
| | | */ |
| | | public final class ImplHuaweiTrampolines { |
| | | private ImplHuaweiTrampolines() {} |
| | | |
| | | public static HuaweiCredential getCredential(HuaweiApp app) { |
| | | return app.getOption().getCredential(); |
| | | } |
| | | |
| | | public static String getAccessToken(HuaweiApp app) { |
| | | return app.getOption().getCredential().getAccessToken(); |
| | | } |
| | | |
| | | public static String getAppId(HuaweiApp app) { |
| | | return app.getOption().getCredential().getAppId(); |
| | | } |
| | | |
| | | public static HttpClient getHttpClient(HuaweiApp app) { |
| | | return app.getOption().getHttpClient(); |
| | | } |
| | | |
| | | public static <T extends HuaweiService> T getService(HuaweiApp app, String id, Class<T> type) { |
| | | return type.cast(app.getService(id)); |
| | | } |
| | | |
| | | public static <T extends HuaweiService> T addService(HuaweiApp app, T service) { |
| | | app.addService(service); |
| | | return service; |
| | | } |
| | | } |
New file |
| | |
| | | /* Copyright 2017 Google Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | |
| | | * 2019.12.15-changed method getHuaweiExecutors |
| | | * 2019.12.15-changed method releaseHuaweiExecutors |
| | | * 2019.12.15-changed method getExecutor |
| | | * 2019.12.15-changed method releaseExecutor |
| | | * Huawei Technologies Co., Ltd. |
| | | * |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.ThreadFactory; |
| | | |
| | | /** |
| | | * An interface that controls the thread pools and thread factories used by the HCM SDK. Each |
| | | * instance of HuaweiApp uses an implementation of this interface to create and manage |
| | | * threads. |
| | | */ |
| | | public abstract class ThreadManager { |
| | | final HuaweiExecutors getHuaweiExecutors(HuaweiApp app) { |
| | | return new HuaweiExecutors(getExecutor(app)); |
| | | } |
| | | |
| | | final void releaseHuaweiExecutors(HuaweiApp app, HuaweiExecutors executor) { |
| | | releaseExecutor(app, executor.userExecutor); |
| | | } |
| | | |
| | | /** |
| | | * Returns the main thread pool for an app. |
| | | * |
| | | * @param app A {@link HuaweiApp} instance. |
| | | * @return A non-null <code>ExecutorService</code> instance. |
| | | */ |
| | | protected abstract ExecutorService getExecutor(HuaweiApp app); |
| | | |
| | | /** |
| | | * Cleans up the thread pool associated with an app. |
| | | * This method is invoked when an app is deleted. |
| | | * |
| | | * @param app A {@link HuaweiApp} instance. |
| | | * @return A non-null <code>ExecutorService</code> instance. |
| | | */ |
| | | protected abstract void releaseExecutor(HuaweiApp app, ExecutorService executor); |
| | | |
| | | /** |
| | | * Returns the <code>ThreadFactory</code> to be used for creating long-lived threads. This is |
| | | * used mainly to create the long-lived worker threads for the scheduled (periodic) tasks started by the SDK. |
| | | * The SDK guarantees clean termination of all threads started via this <code>ThreadFactory</code>, when the user |
| | | * calls {@link HuaweiApp#delete()}. |
| | | * |
| | | * <p>If long-lived threads cannot be supported in the current runtime, this method may |
| | | * throw a {@code RuntimeException}. |
| | | * |
| | | * @return A non-null <code>ThreadFactory</code>. |
| | | */ |
| | | protected abstract ThreadFactory getThreadFactory(); |
| | | |
| | | static final class HuaweiExecutors { |
| | | private ExecutorService userExecutor; |
| | | |
| | | private HuaweiExecutors(ExecutorService userExecutor) { |
| | | ValidatorUtils.checkArgument(userExecutor != null, "ExecutorService must not be null"); |
| | | this.userExecutor = userExecutor; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* Copyright 2017 Google Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | |
| | | * 2019.12.15-changed constructor TokenRefresher |
| | | * Huawei Technologies Co., Ltd. |
| | | * |
| | | */ |
| | | package com.huawei.push.messaging; |
| | | |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.util.concurrent.Future; |
| | | |
| | | /** |
| | | * Utility class for scheduling proactive token refresh events. Each HuaweiApp should have |
| | | * its own instance of this class. TokenRefresher schedules token refresh events when token is expired. |
| | | * |
| | | * <p>This class is thread safe. It will handle only one token change event at a time. It also |
| | | * cancels any pending token refresh events, before scheduling a new one. |
| | | */ |
| | | public class TokenRefresher { |
| | | private static final Logger logger = LoggerFactory.getLogger(TokenRefresher.class); |
| | | |
| | | private HuaweiApp app; |
| | | private HuaweiCredential credential; |
| | | |
| | | private Future future; |
| | | |
| | | public TokenRefresher(HuaweiApp app) { |
| | | ValidatorUtils.checkArgument(app != null, "app must not be null"); |
| | | this.app = app; |
| | | this.credential = app.getOption().getCredential(); |
| | | } |
| | | |
| | | protected void scheduleNext(Runnable task, long initialDelay, long period) { |
| | | logger.debug("Scheduling next token refresh in {} milliseconds", period); |
| | | try { |
| | | future = app.schedule(task, initialDelay, period); |
| | | } catch (UnsupportedOperationException e) { |
| | | logger.debug("Failed to schedule token refresh event", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Schedule a forced token refresh to be executed after a specified period. |
| | | * |
| | | * @param period in milliseconds, after which the token should be forcibly refreshed. |
| | | */ |
| | | public void scheduleRefresh(final long period) { |
| | | cancelPrevious(); |
| | | scheduleNext(() -> credential.refreshToken(), period, period); |
| | | } |
| | | |
| | | private void cancelPrevious() { |
| | | if (future != null) { |
| | | future.cancel(true); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Starts the TokenRefresher if not already started. Starts refreshing when token is expired. If no active |
| | | * token is present, or if the available token is expired soon, this will also refresh immediately. |
| | | */ |
| | | final synchronized void start() { |
| | | logger.debug("Starting the proactive token refresher"); |
| | | String accessToken = credential.getAccessToken(); |
| | | long refreshDelay; |
| | | if (accessToken == null || StringUtils.isEmpty(accessToken)) { |
| | | credential.refreshToken(); |
| | | } |
| | | |
| | | refreshDelay = credential.getExpireIn(); |
| | | |
| | | scheduleRefresh(refreshDelay); |
| | | } |
| | | |
| | | final synchronized void stop() { |
| | | cancelPrevious(); |
| | | logger.debug("Stopped the proactive token refresher"); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.model; |
| | | |
| | | public enum Importance { |
| | | /** |
| | | * LOW |
| | | */ |
| | | LOW("LOW"), |
| | | |
| | | /** |
| | | * NORMAL |
| | | */ |
| | | NORMAL("NORMAL"), |
| | | |
| | | /** |
| | | * HIGH |
| | | */ |
| | | HIGH("HIGH"); |
| | | |
| | | private String value; |
| | | |
| | | private Importance(String value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | /** |
| | | * Gets value * |
| | | * |
| | | * @return the value |
| | | */ |
| | | public String getValue() { |
| | | return value; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.model; |
| | | |
| | | public enum TopicOperation { |
| | | SUBSCRIBE("subscribe"), |
| | | UNSUBSCRIBE("unsubscribe"), |
| | | LIST("list"); |
| | | |
| | | private String value; |
| | | |
| | | private TopicOperation(String value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | /** |
| | | * Gets value * |
| | | * |
| | | * @return the value |
| | | */ |
| | | public String getValue() { |
| | | return value; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.model; |
| | | |
| | | public enum Urgency { |
| | | HIGH("HIGH"), |
| | | NORMAL("NORMAL"); |
| | | |
| | | private String value; |
| | | |
| | | private Urgency(String value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | /** |
| | | * Gets value * |
| | | * |
| | | * @return the value |
| | | */ |
| | | public String getValue() { |
| | | return value; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.model; |
| | | |
| | | public enum Visibility { |
| | | VISIBILITY_UNSPECIFIED("VISIBILITY_UNSPECIFIED"), |
| | | PRIVATE("PRIVATE"), |
| | | PUBLIC("PUBLIC"), |
| | | SECRET("SECRET"); |
| | | |
| | | private String value; |
| | | |
| | | private Visibility(String value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | /** |
| | | * Gets value * |
| | | * |
| | | * @return the value |
| | | */ |
| | | public String getValue() { |
| | | return value; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.reponse; |
| | | |
| | | /** |
| | | * A class of reponse which exposed to developer |
| | | */ |
| | | public class SendResponse { |
| | | private final String code; |
| | | private final String msg; |
| | | private final String requestId; |
| | | |
| | | |
| | | protected SendResponse(String coede, String msg, String requestId) { |
| | | this.code = coede; |
| | | this.msg = msg; |
| | | this.requestId = requestId; |
| | | } |
| | | |
| | | public String getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public String getMsg() { |
| | | return msg; |
| | | } |
| | | |
| | | public String getRequestId() { |
| | | return requestId; |
| | | } |
| | | |
| | | public static SendResponse fromCode(String coede, String msg, String requestId) { |
| | | return new SendResponse(coede, msg, requestId); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.reponse; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | |
| | | public class TopicListResponse extends SendResponse { |
| | | private final JSONArray topics; |
| | | |
| | | public JSONArray getTopics() { |
| | | return topics; |
| | | } |
| | | |
| | | private TopicListResponse(String code, String msg, String requestId, JSONArray topics) { |
| | | super(code, msg, requestId); |
| | | this.topics = topics; |
| | | } |
| | | |
| | | public static TopicListResponse fromCode(String code, String msg, String requestId, JSONArray topics) { |
| | | return new TopicListResponse(code, msg, requestId, topics); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.reponse; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | |
| | | public final class TopicSendResponse extends SendResponse { |
| | | private final Integer failureCount; |
| | | private final Integer successCount; |
| | | private final JSONArray errors; |
| | | |
| | | public Integer getFailureCount() { |
| | | return failureCount; |
| | | } |
| | | |
| | | public Integer getSuccessCount() { |
| | | return successCount; |
| | | } |
| | | |
| | | public JSONArray getErrors() { |
| | | return errors; |
| | | } |
| | | |
| | | private TopicSendResponse(String code, String msg, String requestId, Integer failureCount, Integer successCount, JSONArray errors) { |
| | | super(code,msg,requestId); |
| | | this.failureCount = failureCount; |
| | | this.successCount = successCount; |
| | | this.errors = errors; |
| | | } |
| | | |
| | | public static TopicSendResponse fromCode(String code, String msg, String requestId,Integer failureCount,Integer successCount,JSONArray errors ) { |
| | | return new TopicSendResponse(code, msg, requestId,failureCount,successCount,errors); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.util; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * A tool for processing collections |
| | | */ |
| | | public class CollectionUtils { |
| | | public CollectionUtils() { |
| | | } |
| | | |
| | | public static boolean isEmpty(Collection<?> collection) { |
| | | return collection == null || collection.isEmpty(); |
| | | } |
| | | |
| | | public static boolean isEmpty(Map<?, ?> map) { |
| | | return map == null || map.isEmpty(); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.util; |
| | | |
| | | import org.apache.http.config.Registry; |
| | | import org.apache.http.config.RegistryBuilder; |
| | | import org.apache.http.conn.socket.ConnectionSocketFactory; |
| | | import org.apache.http.conn.socket.PlainConnectionSocketFactory; |
| | | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.TrustManager; |
| | | import javax.net.ssl.X509TrustManager; |
| | | import java.security.KeyManagementException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.security.cert.CertificateException; |
| | | |
| | | /** |
| | | * A tool for ignoring ssl when creating httpclient |
| | | */ |
| | | public class IgnoreSSLUtils { |
| | | private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { |
| | | SSLContext sc = SSLContext.getInstance("TLSv1.2"); |
| | | |
| | | X509TrustManager trustManager = new X509TrustManager() { |
| | | @Override |
| | | public void checkClientTrusted( |
| | | java.security.cert.X509Certificate[] paramArrayOfX509Certificate, |
| | | String paramString) throws CertificateException { |
| | | } |
| | | |
| | | @Override |
| | | public void checkServerTrusted( |
| | | java.security.cert.X509Certificate[] paramArrayOfX509Certificate, |
| | | String paramString) throws CertificateException { |
| | | } |
| | | |
| | | @Override |
| | | public java.security.cert.X509Certificate[] getAcceptedIssuers() { |
| | | return null; |
| | | } |
| | | }; |
| | | |
| | | sc.init(null, new TrustManager[]{trustManager}, null); |
| | | return sc; |
| | | } |
| | | |
| | | /** |
| | | * for ignoring verify SSL |
| | | */ |
| | | public static CloseableHttpClient createClient() throws KeyManagementException, NoSuchAlgorithmException { |
| | | SSLContext sslcontext = createIgnoreVerifySSL(); |
| | | |
| | | Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() |
| | | .register("http", PlainConnectionSocketFactory.INSTANCE) |
| | | .register("https", new SSLConnectionSocketFactory(sslcontext)) |
| | | .build(); |
| | | PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); |
| | | HttpClients.custom().setConnectionManager(connManager); |
| | | |
| | | return HttpClients.custom().setConnectionManager(connManager).build(); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (c) Huawei Technologies Co., Ltd. 2019-2024. All rights reserved. |
| | | */ |
| | | package com.huawei.push.util; |
| | | |
| | | import com.huawei.push.messaging.HuaweiApp; |
| | | import com.huawei.push.messaging.HuaweiCredential; |
| | | import com.huawei.push.messaging.HuaweiOption; |
| | | |
| | | import java.util.ResourceBundle; |
| | | |
| | | public class InitAppUtils { |
| | | |
| | | public static HuaweiApp initializeApp(String appId, String appSecret) { |
| | | HuaweiCredential credential = HuaweiCredential.builder() |
| | | .setAppId(appId) |
| | | .setAppSecret(appSecret) |
| | | .build(); |
| | | |
| | | // Create HuaweiOption |
| | | HuaweiOption option = HuaweiOption.builder() |
| | | .setCredential(credential) |
| | | .build(); |
| | | |
| | | // Initialize HuaweiApp |
| | | // return HuaweiApp.initializeApp(option); |
| | | return HuaweiApp.getInstance(option); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.util; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * A tool for processing the responce code |
| | | */ |
| | | public class ResponceCodeProcesser { |
| | | private static final Map<Integer, String> codeMap = new HashMap<Integer, String>() { |
| | | { |
| | | put(80000000, "Success"); |
| | | put(80100000, "Some tokens are right, the others are illegal"); |
| | | put(80100001, "Parameters check error"); |
| | | put(80100002, "Token number should be one when send sys message"); |
| | | put(80100003, "Message structure error"); |
| | | put(80100004, "TTL is less than current time, please check"); |
| | | put(80100013, "Collapse_key is illegal, please check"); |
| | | put(80100016, "Message contians sensitive information, please check"); |
| | | put(80200001, "Oauth authentication error"); |
| | | put(80200003, "Oauth Token expired"); |
| | | put(80300002, "APP is forbidden to send"); |
| | | put(80300007, "Invalid Token"); |
| | | put(80300008, "The message body size exceeds the default value set by the system (4K)"); |
| | | put(80300010, "Tokens exceed the default value"); |
| | | put(81000001, "System inner error"); |
| | | put(82000001, "GroupKey or groupName error"); |
| | | put(82000002, "GroupKey and groupName do not match"); |
| | | put(82000003, "Token array is null"); |
| | | put(82000004, "Group do not exist"); |
| | | put(82000005, "Group do not belond to this app"); |
| | | put(82000006, "Token array or group number is transfinited"); |
| | | put(82000007, "Invalid topic"); |
| | | put(82000008, "Token array null or transfinited"); |
| | | put(82000009, "Topic num transfinited, at most 2000"); |
| | | put(82000010, "Some token is wrong"); |
| | | put(82000011, "Token is null"); |
| | | put(82000012, "Data storage location is not selected"); |
| | | put(82000013, "Data storage location does not match the actual data"); |
| | | } |
| | | }; |
| | | |
| | | public static String process(Integer code) { |
| | | return codeMap.getOrDefault(code, "Unknown code"); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.util; |
| | | |
| | | /** |
| | | * A tool for validating the parameters |
| | | */ |
| | | public class ValidatorUtils { |
| | | |
| | | public static void checkArgument(boolean expression) { |
| | | if (!expression) { |
| | | throw new IllegalArgumentException(); |
| | | } |
| | | } |
| | | |
| | | public static void checkArgument(boolean expression, Object errorMessage) { |
| | | if (!expression) { |
| | | throw new IllegalArgumentException(String.valueOf(errorMessage)); |
| | | } |
| | | } |
| | | |
| | | public static void checkState(boolean expression, Object errorMessage) { |
| | | if (!expression) { |
| | | throw new IllegalStateException(String.valueOf(errorMessage)); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.huawei.push.util.push; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.google.gson.Gson; |
| | | import com.huawei.push.android.AndroidNotification; |
| | | import com.huawei.push.android.ClickAction; |
| | | import com.huawei.push.message.AndroidConfig; |
| | | import com.huawei.push.messaging.HuaweiApp; |
| | | import com.huawei.push.messaging.HuaweiMessaging; |
| | | import com.huawei.push.reponse.SendResponse; |
| | | import com.huawei.push.util.InitAppUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.yeshi.utils.push.entity.PushAppInfo; |
| | | import org.yeshi.utils.push.entity.PushMessage; |
| | | import org.yeshi.utils.push.exception.MeiZuPushException; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.net.URLEncoder; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * 华为推送 |
| | | * sdk链接:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Examples-V5/server-sample-code-0000001050986079-V5 |
| | | */ |
| | | public class HuaWeiPushUtil { |
| | | |
| | | static Logger logger = LoggerFactory.getLogger(HuaWeiPushUtil.class); |
| | | |
| | | private static AndroidNotification createMessage(PushMessage message) { |
| | | String title = message.getTitle(); |
| | | String content = message.getContent(); |
| | | while (title.length() > 40 - 3) { |
| | | title = title.substring(0, title.length() - 1); |
| | | } |
| | | if (title.length() == 40 - 3) { |
| | | title += "..."; |
| | | } |
| | | |
| | | while (content.length() > 1024 - 3) { |
| | | content = content.substring(0, content.length() - 1); |
| | | } |
| | | |
| | | if (content.length() == 1024 - 3) { |
| | | title += "..."; |
| | | } |
| | | String uri = String.format("intent://%s?#Intent;scheme=%s;launchFlags=0x4000000;", message.getActivityHostPath(), message.getActivityScheme()); |
| | | //增加Activity的跳转参数 |
| | | Map<String, String> activityParams = message.getActivityParams(); |
| | | for (Iterator<String> its = activityParams.keySet().iterator(); its.hasNext(); ) { |
| | | String k = its.next(); |
| | | logger.info("activityParams:{}-{}", k, activityParams.get(k)); |
| | | try { |
| | | if (activityParams.get(k) != null) { |
| | | uri += String.format("S.%s=%s;", k, URLEncoder.encode(activityParams.get(k), "UTF-8")); |
| | | } |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | uri += "end"; |
| | | |
| | | //参数说明链接:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/https-send-api-0000001050986197-V5 |
| | | AndroidNotification androidNotification = AndroidNotification.builder() |
| | | .setTitle(title) |
| | | .setBody(content) |
| | | |
| | | .setClickAction(ClickAction.builder() |
| | | //消息点击行为类型,取值如下: |
| | | //1:打开应用自定义页面 |
| | | //2:点击后打开特定URL |
| | | //3:点击后打开应用 |
| | | .setType(1) |
| | | //设置打开特定URL,本字段填写需要打开的URL, 当type为2时必选。 |
| | | // .setUrl("https://www.huawei.com") |
| | | //自定义页面中intent的实现,请参见指定intent参数。 |
| | | //当type为1时,字段intent和action至少二选一。 |
| | | .setIntent(uri) |
| | | .build()) |
| | | //0:默认样式 |
| | | //1:大文本样式 |
| | | //3:Inbox样式 |
| | | // .setStyle(1) |
| | | .build(); |
| | | |
| | | return androidNotification; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 推送通知 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @param bigTag |
| | | * @param tokens 不能超过1000个 |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationByTokens(PushAppInfo appInfo, PushMessage message,String bigTag, List<String> tokens) throws Exception { |
| | | HuaweiApp app = InitAppUtils.initializeApp(appInfo.getAppId(), appInfo.getAppSecret()); |
| | | HuaweiMessaging huaweiMessaging = HuaweiMessaging.getInstance(app); |
| | | |
| | | AndroidNotification androidNotification = createMessage(message); |
| | | |
| | | //参数说明:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/https-send-api-0000001050986197-V5#ZH-CN_TOPIC_0000001124288117__p837521812163 |
| | | AndroidConfig androidConfig = AndroidConfig.builder().setCollapseKey(-1) |
| | | //透传消息投递优先级,取值如下: |
| | | // |
| | | //HIGH |
| | | //NORMAL |
| | | //设置为HIGH时需要申请权限,请参见申请特殊权限。 |
| | | // |
| | | //HIGH级别消息到达用户手机时可强制拉起应用进程。 |
| | | // .setUrgency(Urgency.HIGH.getValue()) |
| | | //消息缓存时间,单位是秒 |
| | | // .setTtl("10000s") |
| | | //批量任务消息标识,消息回执时会返回给应用服务器,应用服务器可以识别bi_tag对消息的下发情况进行统计分析。 |
| | | .setBiTag(bigTag) |
| | | .setNotification(androidNotification) |
| | | .build(); |
| | | |
| | | com.huawei.push.message.Message msg = com.huawei.push.message.Message.builder() |
| | | .setAndroidConfig(androidConfig) |
| | | .addAllToken(tokens) |
| | | .build(); |
| | | |
| | | SendResponse response = huaweiMessaging.sendMessage(msg); |
| | | |
| | | logger.info("华为推送响应结果:{}", new Gson().toJson(response)); |
| | | return response.getRequestId(); |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) { |
| | | PushAppInfo appInfo = new PushAppInfo("104190661", "", "5acdb54adb1b99c80a7a68b3bacdfea45c342df0535f040304ebb343c929b3bc"); |
| | | appInfo.setPackageName("com.tejia.lijin"); |
| | | Map<String, String> activityParams = new HashMap<>(); |
| | | activityParams.put("activity", "com.tejia.lijin.app.ui.PushOpenClickActivity"); |
| | | JSONObject jumpParams = new JSONObject(); |
| | | jumpParams.put("url", "https://s.click.taobao.com/KnCv9iu"); |
| | | jumpParams.put("from", "push"); |
| | | activityParams.put("params", jumpParams.toJSONString()); |
| | | activityParams.put("type", "baichuan"); |
| | | PushMessage message = new PushMessage("大家好", "大家下午号", null, "tejiapush", "com.huawei.codelabpush/deeplink", activityParams); |
| | | |
| | | String[] ids = new String[]{ |
| | | "IQAAAACy0jK5AACFYBY3hZ7tobGQokkDBMNYPPqx_XZuIyMhiqyG8wuJoy099BmeJlIW2vIlqPXArpMw8a-av7ZZPRfBAgRQPjq317-Fvf4PQ3dyDg", "IQAAAACy0jK5AACR2ZSxytr2xPCaNh9ejS56WZphjyQlp3RaCeePbrnpd0GanNYYpQztD32lgSmOlEL6GjMBBsLyK8g4Qo59jsPMoMwZbMBk_gppEA", "IQAAAACy0jK5AAC3fru7bLf-Bsk8QuNJOSPCUi82ZHtN93YPPbbwCdd3IARs_RON3NfZ2a6uWf3yp5hzW-eKy4vIE_5qWqCUeDsaKRsCtzG1-8smIQ" |
| | | }; |
| | | |
| | | try { |
| | | HuaWeiPushUtil.pushNotificationByTokens(appInfo, message,"null", Arrays.asList(ids)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } |
| | | |
| | | private static class AuthTokenInfo { |
| | | public String token; |
| | | public long expireTime; |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.huawei.push.util.push; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.google.gson.Gson; |
| | | import com.meizu.push.sdk.constant.PushType; |
| | | import com.meizu.push.sdk.server.IFlymePush; |
| | | import com.meizu.push.sdk.server.constant.ResultPack; |
| | | import com.meizu.push.sdk.server.model.push.PushResult; |
| | | import com.meizu.push.sdk.server.model.push.VarnishedMessage; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.yeshi.utils.push.entity.PushAppInfo; |
| | | import org.yeshi.utils.push.entity.PushMessage; |
| | | import org.yeshi.utils.push.exception.MeiZuPushException; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * 魅族推送 |
| | | * 推送文档:http://open.res.flyme.cn/fileserver/upload/file/201803/e174a5709f134f64aae3fb168aec8ea3.pdf |
| | | */ |
| | | public class MeiZuPushUtil { |
| | | |
| | | static Logger logger = LoggerFactory.getLogger(MeiZuPushUtil.class); |
| | | |
| | | private static VarnishedMessage createMessage(PushAppInfo appInfo, PushMessage message) { |
| | | VarnishedMessage.Builder builder = new VarnishedMessage.Builder().appId(Long.parseLong(appInfo.getAppId())) |
| | | .title(message.getTitle()) |
| | | .content(message.getContent()) |
| | | //点击动作 (0,"打开应用"),(1,"打开应用页面"),(2,"打 开URI页面"),(3, "应用客户端自定义")【非必填, 默认值为0】 |
| | | .clickType(1); |
| | | if (message.getActivity() != null) { |
| | | builder = builder.activity(message.getActivity()); |
| | | } |
| | | if (message.getActivityParams() != null && message.getActivityParams().size() > 0) { |
| | | JSONObject params = new JSONObject(); |
| | | for (Iterator<String> its = message.getActivityParams().keySet().iterator(); its.hasNext(); ) { |
| | | String key = its.next(); |
| | | params.put(key, message.getActivityParams().get(key)); |
| | | } |
| | | builder = builder.parameters(params); |
| | | } |
| | | return builder.build(); |
| | | } |
| | | |
| | | /** |
| | | * 推送通知 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @param pushIds 不能超过1000个 |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationByPushId(PushAppInfo appInfo, PushMessage message, List<String> pushIds) throws IOException, MeiZuPushException { |
| | | //推送标题限制字数1-32,推送内容限制字数1-100 |
| | | IFlymePush push = new IFlymePush(appInfo.getAppSecret()); |
| | | VarnishedMessage msg = createMessage(appInfo, message); |
| | | ResultPack<PushResult> result = push.pushMessage(msg, pushIds, 2); |
| | | logger.info("MEIZU推送响应结果:{}", result.code() + "-" + result.comment()); |
| | | if (result.isSucceed()) { |
| | | return result.value().getMsgId(); |
| | | } else { |
| | | throw new MeiZuPushException(result.code(), result.comment()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 推送所有 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationAll(PushAppInfo appInfo, PushMessage message) throws IOException, MeiZuPushException { |
| | | IFlymePush push = new IFlymePush(appInfo.getAppSecret()); |
| | | VarnishedMessage msg = createMessage(appInfo, message); |
| | | ResultPack<Long> result = push.pushToApp(PushType.STATUSBAR, msg); |
| | | if (result.isSucceed()) { |
| | | return result.value() + ""; |
| | | } else { |
| | | throw new MeiZuPushException(result.code(), result.comment()); |
| | | } |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) { |
| | | PushAppInfo appInfo = new PushAppInfo("139085", "dc40ea74e19948a683cb1876d5a8813e", "6497adb8bde044c6a32c0a2766332ca3"); |
| | | Map<String, String> activityParams = new HashMap<>(); |
| | | activityParams.put("activity", "test"); |
| | | JSONObject jumpParams = new JSONObject(); |
| | | jumpParams.put("id", 123123); |
| | | activityParams.put("params", jumpParams.toJSONString()); |
| | | |
| | | PushMessage message = new PushMessage("你好啊", "下午好,hello world", "com.weikou.beibeivideo.ui.push.OpenClickActivity", null, null, activityParams); |
| | | |
| | | String[] ids = new String[]{ |
| | | "UCI4e0f4070047c4949057e76446d6474484500447b05" |
| | | }; |
| | | |
| | | try { |
| | | MeiZuPushUtil.pushNotificationByPushId(appInfo, message, Arrays.asList(ids)); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } catch (MeiZuPushException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.huawei.push.util.push; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.google.gson.Gson; |
| | | import com.ks.push.utils.Constant; |
| | | import com.oppo.push.server.*; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.yeshi.utils.StringUtil; |
| | | import org.yeshi.utils.push.entity.PushAppInfo; |
| | | import org.yeshi.utils.push.entity.PushMessage; |
| | | import org.yeshi.utils.push.exception.MeiZuPushException; |
| | | import org.yeshi.utils.push.exception.OppoPushException; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * OPPO推送 |
| | | * 推送文档:https://open.oppomobile.com/wiki/doc#id=10203 |
| | | */ |
| | | public class OppoPushUtil { |
| | | |
| | | static Logger logger = LoggerFactory.getLogger(OppoPushUtil.class); |
| | | |
| | | private static Notification getNotification(PushMessage message) { |
| | | Notification notification = new Notification(); |
| | | //推送回执 |
| | | notification.setCallBackUrl(Constant.PUSH_CALLBACK_OPPO_URL); |
| | | String title = message.getTitle(); |
| | | String content = message.getContent(); |
| | | if (title.length() > 50) { |
| | | title = title.substring(0, 50 - 3) + "..."; |
| | | } |
| | | if (content.length() > 50) { |
| | | content = content.substring(0, 50 - 3) + "..."; |
| | | } |
| | | /** |
| | | * 以下参数必填项 |
| | | */ |
| | | //字数限制1~32 |
| | | notification.setTitle(title); |
| | | //字数限制200以内,中英文均以一个计算 |
| | | notification.setContent(content); |
| | | /** |
| | | * 以下参数非必填项, 如果需要使用可以参考OPPO push服务端api文档进行设置 |
| | | */ |
| | | //通知栏样式 1. 标准样式 2. 长文本样式 3. 大图样式 【非必填,默认1-标准样式】 |
| | | notification.setStyle(1); |
| | | // App开发者自定义消息Id,OPPO推送平台根据此ID做去重处理,对于广播推送相同appMessageId只会保存一次,对于单推相同appMessageId只会推送一次 |
| | | notification.setAppMessageId(UUID.randomUUID().toString()); |
| | | // 应用接收消息到达回执的回调URL,字数限制200以内,中英文均以一个计算 |
| | | // notification.setCallBackUrl("http://www.test.com"); |
| | | // App开发者自定义回执参数,字数限制50以内,中英文均以一个计算 |
| | | // notification.setCallBackParameter(""); |
| | | // 点击动作类型0,启动应用;1,打开应用内页(activity的intent action);2,打开网页;4,打开应用内页(activity);【非必填,默认值为0】;5,Intent scheme URL |
| | | notification.setClickActionType(4); |
| | | // 应用内页地址【click_action_type为1或4时必填,长度500】 |
| | | notification.setClickActionActivity(message.getActivity()); |
| | | // 网页地址【click_action_type为2必填,长度500】 |
| | | // notification.setClickActionUrl("http://www.test.com"); |
| | | |
| | | if (message.getActivityParams() != null && message.getActivityParams().size() > 0) { |
| | | JSONObject params = new JSONObject(); |
| | | for (Iterator<String> its = message.getActivityParams().keySet().iterator(); its.hasNext(); ) { |
| | | String key = its.next(); |
| | | params.put(key, message.getActivityParams().get(key)); |
| | | } |
| | | // 动作参数,打开应用内页或网页时传递给应用或网页【JSON格式,非必填】,字符数不能超过4K,示例:{"key1":"value1","key2":"value2"} |
| | | notification.setActionParameters(params.toJSONString()); |
| | | } |
| | | |
| | | |
| | | // 展示类型 (0, “即时”),(1, “定时”) |
| | | notification.setShowTimeType(0); |
| | | // 定时展示开始时间(根据time_zone转换成当地时间),时间的毫秒数 |
| | | // notification.setShowStartTime(System.currentTimeMillis() + 1000 * 60 * 3); |
| | | // 定时展示结束时间(根据time_zone转换成当地时间),时间的毫秒数 |
| | | // notification.setShowEndTime(System.currentTimeMillis() + 1000 * 60 * 5); |
| | | // 是否进离线消息,【非必填,默认为True】 |
| | | notification.setOffLine(true); |
| | | // 离线消息的存活时间(time_to_live) (单位:秒), 【off_line值为true时,必填,最长3天】 |
| | | notification.setOffLineTtl(24 * 3600); |
| | | // 时区,默认值:(GMT+08:00)北京,香港,新加坡 |
| | | // notification.setTimeZone("GMT+08:00"); |
| | | // 0:不限联网方式, 1:仅wifi推送 |
| | | notification.setNetworkType(0); |
| | | //若推送消息时不带通道推送, Android 8及以上的手机将收不到消息 |
| | | notification.setChannelId("channel_android"); |
| | | return notification; |
| | | } |
| | | |
| | | /** |
| | | * 推送通知 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @param regIds 不能超过1000个 |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationByRegIds(PushAppInfo appInfo, PushMessage message, List<String> regIds) throws Exception, OppoPushException { |
| | | //推送标题限制字数1-32,推送内容限制字数1-100 |
| | | Sender sender = new Sender(appInfo.getAppKey(), appInfo.getAppSecret()); |
| | | Result result = null; |
| | | if (regIds.size() > 1) { |
| | | Map batch = new HashMap(); // batch最大为1000 |
| | | for (String regId : regIds) { |
| | | batch.put(Target.build(regId), getNotification(message)); |
| | | } |
| | | result = sender.unicastBatchNotification(batch); //发送批量单推消息 |
| | | } else { |
| | | Target target = Target.build(regIds.get(0)); //创建发送对象 |
| | | result = sender.unicastNotification(getNotification(message), target); //发送单推消息 |
| | | } |
| | | logger.info("OPPO推送响应结果:{}", new Gson().toJson(result)); |
| | | if (result.getStatusCode() == 200) { |
| | | if (result.getReturnCode().getCode() == 0) { |
| | | return result.getMessageId(); |
| | | } else { |
| | | throw new OppoPushException(result.getReturnCode().getCode() + "", result.getReturnCode().getMessage()); |
| | | } |
| | | } else { |
| | | throw new OppoPushException("网络请求出错"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 推送所有 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationAll(PushAppInfo appInfo, PushMessage message, List<String> regIds) throws Exception, OppoPushException { |
| | | Sender sender = new Sender(appInfo.getAppKey(), appInfo.getAppSecret()); |
| | | Notification broadNotification = getNotification(message);// 创建通知栏消息体 |
| | | Result saveResult = sender.saveNotification(broadNotification); // 发送保存消息体请求 |
| | | saveResult.getStatusCode(); // 获取http请求状态码 |
| | | saveResult.getReturnCode(); // 获取平台返回码 |
| | | String messageId = saveResult.getMessageId(); //获取messageId |
| | | Target target = new Target(); // 创建广播目标 |
| | | target.setTargetValue(StringUtil.concat(regIds, ";")); |
| | | Result broadResult = sender.broadcastNotification(messageId, target); // 发送广播消息 |
| | | broadResult.getTaskId(); // 获取广播taskId |
| | | List<Result.BroadcastErrorResult> errorList = broadResult.getBroadcastErrorResults(); |
| | | if (errorList.size() > 0) { // 如果大小为0,代表所有目标发送成功 |
| | | for (Result.BroadcastErrorResult error : errorList) { |
| | | error.getErrorCode(); // 错误码 |
| | | error.getTargetValue(); // 目标 |
| | | } |
| | | return broadResult.getTaskId(); |
| | | } else { |
| | | return broadResult.getTaskId(); |
| | | } |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) { |
| | | PushAppInfo appInfo = new PushAppInfo("30514447", "78b911aa08e1468baf24ddea6c7ca23e", "fda37b51cc7f4d4d8b3d326455ec58c0"); |
| | | Map<String, String> activityParams = new HashMap<>(); |
| | | activityParams.put("activity", "test"); |
| | | JSONObject jumpParams = new JSONObject(); |
| | | jumpParams.put("id", 123123); |
| | | activityParams.put("params", jumpParams.toJSONString()); |
| | | |
| | | PushMessage message = new PushMessage("你好啊", "下午好,hello world", "com.weikou.beibeivideo.ui.push.OpenClickActivity", null, null, activityParams); |
| | | |
| | | String[] ids = new String[]{ |
| | | "OPPO_CN_fbaf9e7431c18d4ac4a08089d124c6ca" |
| | | }; |
| | | |
| | | try { |
| | | OppoPushUtil.pushNotificationAll(appInfo, message, Arrays.asList(ids)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.huawei.push.util.push; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.google.gson.Gson; |
| | | import com.vivo.push.sdk.notofication.Message; |
| | | import com.vivo.push.sdk.notofication.Result; |
| | | import com.vivo.push.sdk.notofication.TargetMessage; |
| | | import com.vivo.push.sdk.server.Sender; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.yeshi.utils.push.entity.PushAppInfo; |
| | | import org.yeshi.utils.push.entity.PushMessage; |
| | | import org.yeshi.utils.push.exception.MeiZuPushException; |
| | | import org.yeshi.utils.push.exception.VIVOPushException; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.net.URLEncoder; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * vivo 推送 |
| | | * 推送文档:https://dev.vivo.com.cn/documentCenter/doc/363 |
| | | */ |
| | | public class VIVOPushUtil { |
| | | |
| | | private static Map<String, AuthTokenInfo> tokenMap = new HashMap<>(); |
| | | |
| | | static Logger logger= LoggerFactory.getLogger(VIVOPushUtil.class); |
| | | |
| | | private static int computeContentLength(String content) { |
| | | int count = 0; |
| | | for (int i = 0; i < content.length(); i++) { |
| | | //英文和数字算一个字符,其他算2个字符 |
| | | if (content.charAt(i) >= 48 && content.charAt(i) <= 57) {//数字 |
| | | count++; |
| | | } else if (content.charAt(i) >= 65 && content.charAt(i) <= 90) {//大写字母 |
| | | count++; |
| | | } else if (content.charAt(i) >= 97 && content.charAt(i) <= 122) {//小写字母 |
| | | count++; |
| | | } else { |
| | | count += 2; |
| | | } |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | |
| | | private static Message.Builder createMessage(PushMessage message) { |
| | | String title = message.getTitle(); |
| | | String content = message.getContent(); |
| | | while (computeContentLength(title) > 40 - 3) { |
| | | title = title.substring(0, title.length() - 1); |
| | | } |
| | | if (computeContentLength(title) == 40 - 3) { |
| | | title += "..."; |
| | | } |
| | | |
| | | while (computeContentLength(content) > 100 - 3) { |
| | | content = content.substring(0, content.length() - 1); |
| | | } |
| | | |
| | | if (computeContentLength(content) == 100 - 3) { |
| | | title += "..."; |
| | | } |
| | | String uri = String.format("intent://%s?#Intent;scheme=%s;launchFlags=0x4000000;", message.getActivityHostPath(), message.getActivityScheme()); |
| | | //增加Activity的跳转参数 |
| | | for (Iterator<String> its = message.getActivityParams().keySet().iterator(); its.hasNext(); ) { |
| | | String k = its.next(); |
| | | try { |
| | | if (message.getActivityParams().get(k) != null) { |
| | | uri += String.format("S.%s=%s;", k, URLEncoder.encode(message.getActivityParams().get(k), "UTF-8")); |
| | | } |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | uri += "end"; |
| | | |
| | | Message.Builder builder = new Message.Builder(); |
| | | builder = builder |
| | | //必填项,设置通知标题(用于通知栏消息),最大20个汉字(一个汉字等于两个英文字符,即最大不超过40个英文字符) |
| | | .title(title) |
| | | //必填项,设置通知内容(用于通知栏消息) 最大50个汉字(一个汉字等于两个英文字符,即最大不超过100个英文字符) |
| | | .content(content) |
| | | //,设置点击跳转类型,value类型支持以下值 1:打开APP首页 2:打开链接 3:自定义 4:打开app内指定页面 |
| | | .skipType(4) |
| | | //跳转类型为2时,跳转内容最大1000个字符, |
| | | //跳转类型为3或4时,跳转内容最大1024个字符 |
| | | .skipContent(uri) |
| | | // 1:无 2:响铃 3:振动 4:响铃和振动 |
| | | .notifyType(4) |
| | | //推送模式 0:正式推送;1:测试推送,不填默认为0 |
| | | .pushMode(message.isTest() ? 1 : 0) |
| | | //消息类型 0:运营类消息,1:系统类消息 |
| | | .classification(1) |
| | | .requestId(UUID.randomUUID().toString()); |
| | | if (message.getActivityParams() != null) { |
| | | builder = builder.clientCustomMap(message.getActivityParams()); |
| | | } |
| | | return builder.timeToLive(3600); |
| | | } |
| | | |
| | | private static Sender getSender(PushAppInfo appInfo) throws Exception { |
| | | Sender sender = new Sender(appInfo.getAppSecret());//注册登录开发平台网站获取到的appSecret |
| | | sender.initPool(20, 10);//设置连接池参数,可选项 |
| | | String appId = appInfo.getAppId(); |
| | | String token = null; |
| | | if (tokenMap.get(appId) == null || tokenMap.get(appId).expireTime < System.currentTimeMillis()) { |
| | | Result result = sender.getToken(Integer.parseInt(appInfo.getAppId()), appInfo.getAppKey());//注册登录开发平台网站获取到的appId和appKey |
| | | token = result.getAuthToken(); |
| | | if (token != null) { |
| | | AuthTokenInfo tokenInfo = new AuthTokenInfo(); |
| | | tokenInfo.expireTime = System.currentTimeMillis() + 1000 * 60 * 20L; |
| | | tokenInfo.token = token; |
| | | tokenMap.put(appId, tokenInfo); |
| | | } |
| | | } |
| | | sender.setAuthToken(tokenMap.get(appId).token); |
| | | |
| | | return sender; |
| | | } |
| | | |
| | | /** |
| | | * 推送通知 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @param regIds 不能超过1000个 |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationByRegIds(PushAppInfo appInfo, PushMessage message, List<String> regIds) throws Exception, VIVOPushException { |
| | | Sender sender = getSender(appInfo); |
| | | Message.Builder builder = createMessage(message); |
| | | Message saveList = builder.build();// 构建要保存的批量推送消息体 |
| | | Result result = null; |
| | | if (regIds.size() > 1) { |
| | | result = sender.saveListPayLoad(saveList);// 发送保存群推消息请求 |
| | | String taskId = result.getTaskId(); |
| | | |
| | | TargetMessage targetMessage = new TargetMessage.Builder() |
| | | .requestId(UUID.randomUUID().toString()) |
| | | .regIds(new HashSet<>(regIds)).taskId(taskId).build();// 构建批量推送的消息体 |
| | | result = sender.sendToList(targetMessage);// 批量推送给用户 |
| | | } else { |
| | | result = sender.sendSingle(builder.regId(regIds.get(0)).build()); |
| | | } |
| | | |
| | | logger.info("VIVO推送响应结果:{}", new Gson().toJson(result)); |
| | | |
| | | if (result.getResult() == 0)// 成功 |
| | | { |
| | | return result.getTaskId(); |
| | | } else { |
| | | throw new VIVOPushException(result.getResult() + "", result.getDesc()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 推送所有(暂未对外开放) |
| | | * // * |
| | | * // * @param appInfo |
| | | * // * @param message |
| | | * // * @return |
| | | * // * @throws IOException |
| | | * // * @throws MeiZuPushException |
| | | * // |
| | | */ |
| | | // public static String pushNotificationAll(PushAppInfo appInfo, PushMessage message) throws Exception, OppoPushException { |
| | | // Sender sender = getSender(appInfo); |
| | | // Message.Builder builder = createMessage(message); |
| | | // Result result = sender.sendToAll(builder.build()); |
| | | // if (result.getResult() == 0)// 成功 |
| | | // { |
| | | // return result.getTaskId(); |
| | | // } else { |
| | | // throw new VIVOPushException(result.getResult() + "", result.getDesc()); |
| | | // } |
| | | // } |
| | | public static void main(String[] args) { |
| | | PushAppInfo appInfo = new PushAppInfo("105477463", "8a622972d8857cd29df47a0754be73be", "14bf9175-bc72-4d9d-bbcd-ba4ca78dc8fe"); |
| | | Map<String, String> activityParams = new HashMap<>(); |
| | | activityParams.put("activity", "com.tejia.lijin.app.ui.invite.ShareBrowserActivity"); |
| | | activityParams.put("type", "web"); |
| | | JSONObject jumpParams = new JSONObject(); |
| | | jumpParams.put("url", "http://www.baidu.com"); |
| | | activityParams.put("params", jumpParams.toJSONString()); |
| | | |
| | | PushMessage message = new PushMessage("祝大家春节快乐", "下午好,hello world", "", "tejiapush", "com.huawei.codelabpush/deeplink", activityParams); |
| | | |
| | | String[] ids = new String[]{ |
| | | "16239830400127746325913" |
| | | }; |
| | | |
| | | try { |
| | | VIVOPushUtil.pushNotificationByRegIds(appInfo, message, Arrays.asList(ids)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } |
| | | |
| | | private static class AuthTokenInfo { |
| | | public String token; |
| | | public long expireTime; |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.huawei.push.util.push; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.google.gson.Gson; |
| | | import com.ks.push.utils.Constant; |
| | | import com.xiaomi.xmpush.server.Constants; |
| | | import com.xiaomi.xmpush.server.Message; |
| | | import com.xiaomi.xmpush.server.Result; |
| | | import com.xiaomi.xmpush.server.Sender; |
| | | import org.json.simple.parser.ParseException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.yeshi.utils.push.entity.PushAppInfo; |
| | | import org.yeshi.utils.push.entity.PushMessage; |
| | | import org.yeshi.utils.push.exception.MeiZuPushException; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.net.URLEncoder; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * 小米推送 |
| | | * 推送文档:https://dev.mi.com/console/doc/detail?pId=1278 |
| | | */ |
| | | public class XiaoMiPushUtil { |
| | | |
| | | static Logger logger = LoggerFactory.getLogger(XiaoMiPushUtil.class); |
| | | |
| | | private static Message createMessage(PushAppInfo appInfo, PushMessage message) { |
| | | String title = message.getTitle(); |
| | | String content = message.getContent(); |
| | | |
| | | if (title.length() > 50) { |
| | | title = title.substring(0, 50 - 3) + "..."; |
| | | } |
| | | if (content.length() > 128) { |
| | | content = content.substring(0, 128 - 3) + "..."; |
| | | } |
| | | //示例:intent:#Intent;component=com.doudou.ysvideo/com.weikou.beibeivideo.ui.push.OpenClickActivity;S.activity=test;S.params=%7B%22id%22%3A%22123123%22%7D;end |
| | | String uri = String.format("intent:#Intent;component=%s/%s;", appInfo.getPackageName(), message.getActivity().replace(appInfo.getPackageName(), "")); |
| | | //增加Activity的跳转参数 |
| | | for (Iterator<String> its = message.getActivityParams().keySet().iterator(); its.hasNext(); ) { |
| | | String k = its.next(); |
| | | try { |
| | | if (message.getActivityParams().get(k) != null) { |
| | | uri += String.format("S.%s=%s;", k, URLEncoder.encode(message.getActivityParams().get(k), "UTF-8")); |
| | | } |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | uri += "end"; |
| | | |
| | | |
| | | Message msg = new Message.Builder() |
| | | //设置在通知栏展示的通知的标题, 不允许全是空白字符, 长度小于50, 一个中英文字符均计算为1(通知栏消息必填) |
| | | .title(title) |
| | | //设置在通知栏展示的通知描述, 不允许全是空白字符, 长度小于128, 一个中英文字符均计算为1(通知栏消息必填) |
| | | .description(content) |
| | | .restrictedPackageName(appInfo.getPackageName()) |
| | | //1:使用默认提示音提示 |
| | | //2:使用默认震动提示 |
| | | //4:使用默认led灯光提示 |
| | | //-1(系统默认值):以上三种效果都有 |
| | | //0:以上三种效果都无,即静默推送。 |
| | | //并且支持1,2,4的任意OR运算来实现声音、震动和闪光灯的任意组合。 |
| | | |
| | | .notifyType(1) // 使用默认提示音提示 |
| | | //可选项, 对app提供一些扩展功能(除了这些扩展功能, |
| | | // 开发者还可以定义一些key和value来控制客户端的行为, |
| | | // 注:key和value的字符数不能超过1024, 至多可以设置10个key-value键值对) |
| | | //.extra() |
| | | .extra(Constants.EXTRA_PARAM_NOTIFY_EFFECT, Constants.NOTIFY_ACTIVITY) |
| | | // 启动Activity的intent uri |
| | | .extra(Constants.EXTRA_PARAM_INTENT_URI, uri) |
| | | //消息回执 https://dev.mi.com/console/doc/detail?pId=1278#_3_6 |
| | | .extra("callback", Constant.PUSH_CALLBACK_XM_URL) |
| | | .extra("callback.param", appInfo.getAppId()) |
| | | .extra("callback.type", "19")//收到消息送达、消息点击和目标设备无效三种状态的回执 |
| | | |
| | | .build(); |
| | | return msg; |
| | | } |
| | | |
| | | /** |
| | | * 推送通知 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @param regIds 不能超过1000个 |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationByRegIds(PushAppInfo appInfo, PushMessage message, List<String> regIds) throws IOException { |
| | | //推送标题限制字数1-32,推送内容限制字数1-100 |
| | | Sender sender = new Sender(appInfo.getAppSecret()); |
| | | Message msg = createMessage(appInfo, message); |
| | | Result result = sender.unionSend(msg, regIds, 3); |
| | | logger.info("小米推送响应结果:{}", new Gson().toJson(result)); |
| | | return result.getMessageId(); |
| | | } |
| | | |
| | | /** |
| | | * 推送所有 |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @return |
| | | * @throws IOException |
| | | * @throws MeiZuPushException |
| | | */ |
| | | public static String pushNotificationAll(PushAppInfo appInfo, PushMessage message) throws IOException, ParseException { |
| | | Sender sender = new Sender(appInfo.getAppSecret()); |
| | | Message msg = createMessage(appInfo, message); |
| | | Result result = sender.broadcastAll(msg, 3); |
| | | logger.info("小米推送响应结果:{}", new Gson().toJson(result)); |
| | | return result.getMessageId(); |
| | | } |
| | | |
| | | |
| | | public static void main(String[] args) { |
| | | PushAppInfo appInfo = new PushAppInfo("2882303761519871448", "5161987181448", "OcdMXvErcGtf1XyXnwrhOg=="); |
| | | appInfo.setPackageName("com.tejia.lijin"); |
| | | Map<String, String> activityParams = new HashMap<>(); |
| | | activityParams.put("activity", "com.weikou.beibeivideo.ui.media.VideoDetailActivity2"); |
| | | JSONObject jumpParams = new JSONObject(); |
| | | jumpParams.put("Id", "8219668"); |
| | | jumpParams.put("Share", 0); |
| | | jumpParams.put("ThirdType", 0); |
| | | activityParams.put("params", jumpParams.toJSONString()); |
| | | |
| | | PushMessage message = new PushMessage("她们创业的那些事儿", "讲述了三个不同年龄、不同性格的女生因缘际会在一起创业的故事,在这条不被看好的创业之路上,她们终将学会,对鸟事一笑置之,不是认输,而是成长!", "com.tejia.lijin.app.ui.PushOpenClickActivity", null, null, activityParams); |
| | | |
| | | String[] ids = new String[]{ |
| | | "t76FQBHolG/YQ9V7qmhtsTbLXNDcCNHfSfNK2k3iKI6B8RYL9FPSWJvXDaBNKy8N" |
| | | }; |
| | | |
| | | try { |
| | | XiaoMiPushUtil.pushNotificationByRegIds(appInfo, message, Arrays.asList(ids)); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | // try { |
| | | // XiaoMiPushUtil.pushNotificationByRegIds(appInfo, message, Arrays.asList(ids)); |
| | | // } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | // } |
| | | |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.webpush; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | |
| | | public class WebActions { |
| | | @JSONField(name = "action") |
| | | private String action; |
| | | |
| | | @JSONField(name = "icon") |
| | | private String icon; |
| | | |
| | | @JSONField(name = "title") |
| | | private String title; |
| | | |
| | | public String getAction() { |
| | | return action; |
| | | } |
| | | |
| | | public String getIcon() { |
| | | return icon; |
| | | } |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public void check(){ |
| | | |
| | | } |
| | | |
| | | public WebActions(Builder builder) { |
| | | this.action = builder.action; |
| | | this.icon = builder.icon; |
| | | this.title = builder.title; |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String action; |
| | | private String icon; |
| | | private String title; |
| | | |
| | | public Builder setAction(String action) { |
| | | this.action = action; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setIcon(String icon) { |
| | | this.icon = icon; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTitle(String title) { |
| | | this.title = title; |
| | | return this; |
| | | } |
| | | |
| | | public WebActions build() { |
| | | return new WebActions(this); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.webpush; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | import java.net.MalformedURLException; |
| | | import java.net.URL; |
| | | |
| | | public class WebHmsOptions { |
| | | @JSONField(name = "link") |
| | | private String link; |
| | | |
| | | public String getLink() { |
| | | return link; |
| | | } |
| | | |
| | | public WebHmsOptions(Builder builder) { |
| | | this.link = builder.link; |
| | | } |
| | | |
| | | public void check() { |
| | | if (!StringUtils.isEmpty(this.link)) { |
| | | try { |
| | | new URL(link); |
| | | } catch (MalformedURLException e) { |
| | | ValidatorUtils.checkArgument(false, "Invalid link"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String link; |
| | | |
| | | public Builder setLink(String link) { |
| | | this.link = link; |
| | | return this; |
| | | } |
| | | |
| | | public WebHmsOptions build() { |
| | | return new WebHmsOptions(this); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.webpush; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.CollectionUtils; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | |
| | | public class WebNotification { |
| | | private static String[] DIR_VALUE = {"auto", "ltr", "rtl"}; |
| | | |
| | | @JSONField(name = "title") |
| | | private String title; |
| | | |
| | | @JSONField(name = "body") |
| | | private String body; |
| | | |
| | | @JSONField(name = "icon") |
| | | private String icon; |
| | | |
| | | @JSONField(name = "image") |
| | | private String image; |
| | | |
| | | @JSONField(name = "lang") |
| | | private String lang; |
| | | |
| | | @JSONField(name = "tag") |
| | | private String tag; |
| | | |
| | | @JSONField(name = "badge") |
| | | private String badge; |
| | | |
| | | @JSONField(name = "dir") |
| | | private String dir; |
| | | |
| | | @JSONField(name = "vibrate") |
| | | private List<Object> vibrate = new ArrayList<Object>(); |
| | | |
| | | @JSONField(name = "renotify") |
| | | private boolean renotify; |
| | | |
| | | @JSONField(name = "require_interaction") |
| | | private boolean requireInteraction; |
| | | |
| | | @JSONField(name = "silent") |
| | | private boolean silent; |
| | | |
| | | @JSONField(name = "timestamp") |
| | | private Long timestamp; |
| | | |
| | | @JSONField(name = "actions") |
| | | private List<WebActions> actions = new ArrayList<WebActions>(); |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public String getBody() { |
| | | return body; |
| | | } |
| | | |
| | | public String getIcon() { |
| | | return icon; |
| | | } |
| | | |
| | | public String getImage() { |
| | | return image; |
| | | } |
| | | |
| | | public String getLang() { |
| | | return lang; |
| | | } |
| | | |
| | | public String getTag() { |
| | | return tag; |
| | | } |
| | | |
| | | public String getBadge() { |
| | | return badge; |
| | | } |
| | | |
| | | public String getDir() { |
| | | return dir; |
| | | } |
| | | |
| | | public List<Object> getVibrate() { |
| | | return vibrate; |
| | | } |
| | | |
| | | public boolean isRenotify() { |
| | | return renotify; |
| | | } |
| | | |
| | | public boolean isRequireInteraction() { |
| | | return requireInteraction; |
| | | } |
| | | |
| | | public boolean isSilent() { |
| | | return silent; |
| | | } |
| | | |
| | | public Long getTimestamp() { |
| | | return timestamp; |
| | | } |
| | | |
| | | public List<WebActions> getActions() { |
| | | return actions; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.dir != null) { |
| | | ValidatorUtils.checkArgument(Arrays.stream(DIR_VALUE).anyMatch(value -> value.equals(dir)), "Invalid dir"); |
| | | } |
| | | if (this.vibrate != null) { |
| | | for (Object obj : vibrate) { |
| | | ValidatorUtils.checkArgument((obj instanceof Double || obj instanceof Integer), "Invalid vibrate"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public WebNotification(Builder builder) { |
| | | this.title = builder.title; |
| | | this.body = builder.body; |
| | | this.icon = builder.icon; |
| | | this.image = builder.image; |
| | | this.lang = builder.lang; |
| | | this.tag = builder.tag; |
| | | this.badge = builder.badge; |
| | | this.dir = builder.dir; |
| | | if (!CollectionUtils.isEmpty(builder.vibrate)) { |
| | | this.vibrate.addAll(builder.vibrate); |
| | | } else { |
| | | this.vibrate = null; |
| | | } |
| | | |
| | | this.renotify = builder.renotify; |
| | | this.requireInteraction = builder.requireInteraction; |
| | | this.silent = builder.silent; |
| | | this.timestamp = builder.timestamp; |
| | | if (!CollectionUtils.isEmpty(builder.actions)) { |
| | | this.actions.addAll(builder.actions); |
| | | } else { |
| | | this.actions = null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String title; |
| | | private String body; |
| | | private String icon; |
| | | private String image; |
| | | private String lang; |
| | | private String tag; |
| | | private String badge; |
| | | private String dir; |
| | | private List<Object> vibrate = new ArrayList<Object>(); |
| | | private boolean renotify; |
| | | private boolean requireInteraction; |
| | | private boolean silent; |
| | | private Long timestamp; |
| | | private List<WebActions> actions = new ArrayList<WebActions>(); |
| | | |
| | | public Builder setTitle(String title) { |
| | | this.title = title; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBody(String body) { |
| | | this.body = body; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setIcon(String icon) { |
| | | this.icon = icon; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setImage(String image) { |
| | | this.image = image; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setLang(String lang) { |
| | | this.lang = lang; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTag(String tag) { |
| | | this.tag = tag; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setBadge(String badge) { |
| | | this.badge = badge; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setDir(String dir) { |
| | | this.dir = dir; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllVibrate(List<Object> vibrate) { |
| | | this.vibrate.addAll(vibrate); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addVibrate(Object vibrate) { |
| | | this.vibrate.add(vibrate); |
| | | return this; |
| | | } |
| | | |
| | | public Builder setRenotify(boolean renotify) { |
| | | this.renotify = renotify; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setRequireInteraction(boolean requireInteraction) { |
| | | this.requireInteraction = requireInteraction; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setSilent(boolean silent) { |
| | | this.silent = silent; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTimestamp(Long timestamp) { |
| | | this.timestamp = timestamp; |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAllActions(List<WebActions> actions) { |
| | | this.actions.addAll(actions); |
| | | return this; |
| | | } |
| | | |
| | | public Builder addAction(WebActions action) { |
| | | this.actions.add(action); |
| | | return this; |
| | | } |
| | | |
| | | public WebNotification build() { |
| | | return new WebNotification(this); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. |
| | | |
| | | Licensed under the Apache License, Version 2.0 (the "License"); |
| | | you may not use this file except in compliance with the License. |
| | | You may obtain a copy of the License at |
| | | |
| | | http://www.apache.org/licenses/LICENSE-2.0 |
| | | |
| | | Unless required by applicable law or agreed to in writing, software |
| | | distributed under the License is distributed on an "AS IS" BASIS, |
| | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | See the License for the specific language governing permissions and |
| | | limitations under the License. |
| | | */ |
| | | package com.huawei.push.webpush; |
| | | |
| | | import com.alibaba.fastjson.annotation.JSONField; |
| | | import com.huawei.push.util.ValidatorUtils; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | public class WebpushHeaders { |
| | | private static String TTL_PATTERN = "[0-9]+|[0-9]+[sS]"; |
| | | |
| | | private static String[] URGENCY_VALUE = {"very-low", "low", "normal", "high"}; |
| | | |
| | | @JSONField(name = "ttl") |
| | | private String ttl; |
| | | |
| | | @JSONField(name = "topic") |
| | | private String topic; |
| | | |
| | | @JSONField(name = "urgency") |
| | | private String urgency; |
| | | |
| | | public String getTtl() { |
| | | return ttl; |
| | | } |
| | | |
| | | public String getTopic() { |
| | | return topic; |
| | | } |
| | | |
| | | public String getUrgency() { |
| | | return urgency; |
| | | } |
| | | |
| | | public WebpushHeaders(Builder builder) { |
| | | this.ttl = builder.ttl; |
| | | this.topic = builder.topic; |
| | | this.urgency = builder.urgency; |
| | | } |
| | | |
| | | public void check() { |
| | | if (this.ttl != null) { |
| | | ValidatorUtils.checkArgument(this.ttl.matches(TTL_PATTERN), "Invalid ttl format"); |
| | | } |
| | | if (this.urgency != null) { |
| | | ValidatorUtils.checkArgument(Arrays.stream(URGENCY_VALUE).anyMatch(value -> value.equals(urgency)),"Invalid urgency"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * builder |
| | | */ |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | | } |
| | | |
| | | public static class Builder { |
| | | private String ttl; |
| | | private String topic; |
| | | private String urgency; |
| | | |
| | | public Builder setTtl(String ttl) { |
| | | this.ttl = ttl; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setTopic(String topic) { |
| | | this.topic = topic; |
| | | return this; |
| | | } |
| | | |
| | | public Builder setUrgency(String urgency) { |
| | | this.urgency = urgency; |
| | | return this; |
| | | } |
| | | |
| | | public WebpushHeaders build() { |
| | | return new WebpushHeaders(this); |
| | | } |
| | | } |
| | | } |
| | |
| | | package com.ks.push; |
| | | |
| | | import com.ks.push.consumer.mq.PushTaskConsumer; |
| | | import com.ks.push.dto.mq.InvalidDeviceTokenInfo; |
| | | import com.ks.push.manager.CMQManager; |
| | | import com.ks.push.manager.PushDeviceTokenManager; |
| | | import com.ks.push.pojo.DO.BPushDeviceToken; |
| | | import com.ks.push.pojo.DO.PushPlatform; |
| | | import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; |
| | | import org.mybatis.spring.annotation.MapperScan; |
| | |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.boot.SpringApplication; |
| | | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| | | import org.springframework.boot.builder.SpringApplicationBuilder; |
| | | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
| | | import org.springframework.context.ApplicationListener; |
| | | import org.springframework.context.event.ContextRefreshedEvent; |
| | | import org.springframework.transaction.annotation.EnableTransactionManagement; |
| | | import org.yeshi.utils.mq.JobThreadExecutorServiceImpl; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.List; |
| | | |
| | | @SpringBootApplication |
| | | @EnableTransactionManagement |
| | |
| | | |
| | | @Resource |
| | | private PushTaskConsumer pushTaskConsumer; |
| | | |
| | | @Resource |
| | | private PushDeviceTokenManager pushDeviceTokenManager; |
| | | |
| | | public static void main(String[] args) { |
| | | SpringApplication.run(PushApplication.class, args); |
| | |
| | | }); |
| | | } |
| | | } |
| | | |
| | | //清理无效token |
| | | new JobThreadExecutorServiceImpl().run(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | List<CMQManager.MQMsgConsumeResult> list = CMQManager.getInstance().consumeInvalidDeviceTokenQueue(16); |
| | | if (list != null) { |
| | | logger.info("清理无效token数量:" + list.size()); |
| | | for (CMQManager.MQMsgConsumeResult result : list) { |
| | | InvalidDeviceTokenInfo tokenInfo = (InvalidDeviceTokenInfo) result.getData(); |
| | | List<BPushDeviceToken> tokenList = pushDeviceTokenManager.list(tokenInfo.getAppCode(), tokenInfo.getPushPlatform(), tokenInfo.getToken(), 1, 20); |
| | | if (tokenList != null) { |
| | | for (BPushDeviceToken token : tokenList) { |
| | | logger.info("清理无效token id-{}" + token.getId()); |
| | | //删除 |
| | | pushDeviceTokenManager.deleteByPrimaryKey(token.getId()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | } |
| | |
| | | package com.ks.push.config; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonAutoDetect; |
| | | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
| | | import com.fasterxml.jackson.annotation.PropertyAccessor; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; |
| | | import org.apache.commons.pool2.impl.GenericObjectPoolConfig; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.cache.annotation.CachingConfigurerSupport; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.data.redis.connection.RedisConnectionFactory; |
| | | import org.springframework.data.redis.connection.RedisPassword; |
| | | import org.springframework.data.redis.connection.RedisStandaloneConfiguration; |
| | | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; |
| | | import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; |
| | | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; |
| | | import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; |
| | | import org.springframework.data.redis.serializer.StringRedisSerializer; |
| | | import redis.clients.jedis.JedisPool; |
| | | import redis.clients.jedis.JedisPoolConfig; |
| | | |
| | | import java.time.Duration; |
| | | |
| | | |
| | | @Configuration |
| | | public class RedisConfig extends CachingConfigurerSupport { |
| | | |
| | | @Value("${spring.redis.host}") |
| | | private String addr; |
| | | @Value("${spring.redis.port}") |
| | | private int port; |
| | | @Value("${spring.redis.timeout}") |
| | | private int timeout; |
| | | @Value("${spring.redis.password}") |
| | | private String auth; |
| | | @Value("${spring.redis.database}") |
| | | private int database; |
| | | @Value("${spring.redis.lettuce.pool.max-active}") |
| | | private int maxActive; |
| | | @Value("${spring.redis.lettuce.pool.max-wait}") |
| | | private int maxWait; |
| | | @Value("${spring.redis.lettuce.pool.max-idle}") |
| | | private int maxIdle; |
| | | @Value("${spring.redis.lettuce.pool.min-idle}") |
| | | private int minIdle; |
| | | @Value("${spring.redis.lettuce.shutdown-timeout}") |
| | | private int shutDownTimeout; |
| | | |
| | | |
| | | @Bean |
| | | public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { |
| | | public LettuceConnectionFactory lettuceConnectionFactory() { |
| | | GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig(); |
| | | genericObjectPoolConfig.setMaxIdle(maxIdle); |
| | | genericObjectPoolConfig.setMinIdle(minIdle); |
| | | genericObjectPoolConfig.setMaxTotal(maxActive); |
| | | genericObjectPoolConfig.setMaxWaitMillis(maxWait); |
| | | genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(1000); |
| | | RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); |
| | | redisStandaloneConfiguration.setDatabase(database); |
| | | redisStandaloneConfiguration.setHostName(addr); |
| | | redisStandaloneConfiguration.setPort(port); |
| | | redisStandaloneConfiguration.setPassword(RedisPassword.of(auth)); |
| | | LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder() |
| | | .commandTimeout(Duration.ofMillis(timeout)) |
| | | .shutdownTimeout(Duration.ofMillis(shutDownTimeout)) |
| | | .poolConfig(genericObjectPoolConfig) |
| | | .build(); |
| | | |
| | | LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig); |
| | | //允许多个连接公用一个物理连接,默认为true |
| | | // factory.setShareNativeConnection(true); |
| | | // 检验链接是否可用,默认为false |
| | | factory.setValidateConnection(true); |
| | | return factory; |
| | | } |
| | | |
| | | @Bean |
| | | public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { |
| | | RedisTemplate<String, Object> template = new RedisTemplate<>(); |
| | | template.setConnectionFactory(factory); |
| | | template.setConnectionFactory(lettuceConnectionFactory); |
| | | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); |
| | | ObjectMapper om = new ObjectMapper(); |
| | | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); |
| | | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); |
| | | om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, |
| | | ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); |
| | | jackson2JsonRedisSerializer.setObjectMapper(om); |
| | | |
| | | |
| | | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); |
| | | // key采用String的序列化方式 |
| | | template.setKeySerializer(stringRedisSerializer); |
| | |
| | | template.afterPropertiesSet(); |
| | | return template; |
| | | } |
| | | |
| | | |
| | | @Bean |
| | | public JedisPool jedisPool() { |
| | | JedisPoolConfig poolConfig = new JedisPoolConfig(); |
| | | poolConfig.setMaxTotal(maxActive); |
| | | poolConfig.setMaxIdle(maxIdle); |
| | | poolConfig.setTestOnBorrow(true); |
| | | return new JedisPool(poolConfig, addr, port, timeout, auth, database); |
| | | } |
| | | } |
| | |
| | | if (platform == null) { |
| | | return; |
| | | } |
| | | logger.info("消费消息开始:{} Thread:{}", platform.name(),Thread.currentThread().getId()); |
| | | // logger.info("消费消息开始:{} Thread:{}", platform.name(), Thread.currentThread().getId()); |
| | | List<CMQManager.MQMsgConsumeResult> resultList = null; |
| | | try { |
| | | resultList = CMQManager.getInstance().consumePushQueue(platform, 1); |
| | | } catch (Exception e) { |
| | | } |
| | | logger.info("消费消息结束:{} Thread:{}", platform.name(),Thread.currentThread().getId()); |
| | | // logger.info("消费消息结束:{} Thread:{}", platform.name(), Thread.currentThread().getId()); |
| | | if (resultList != null) { |
| | | for (CMQManager.MQMsgConsumeResult result : resultList) { |
| | | try { |
| | |
| | | BPushPlatformAppInfo platformAppInfo = bPushPlatformAppInfoManager.selectByAppCodeAndPlatform(task.getAppCode(), platform); |
| | | if (platformAppInfo != null) { |
| | | try { |
| | | PushUtil.pushNotifyCation(platform, platformAppInfo.getPushAppInfo(), task.getMessage(), dataSet.getDeviceTokenList()); |
| | | logger.info("推送任务执行成功,taskId-{},batchId-{}", dataSet.getTaskId(), dataSet.getBatchId()); |
| | | PushUtil.pushNotifyCation(platform, platformAppInfo.getPushAppInfo(), task.getMessage(), task.getId() + "#" + dataSet.getBatchId(), dataSet.getDeviceTokenList()); |
| | | logger.info("{}推送任务执行成功,taskId-{},batchId-{}", platform.name(), dataSet.getTaskId(), dataSet.getBatchId()); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | logger.error("推送出错:ttaskId-{},batchId-{},错误原因:{}", task.getId(), dataSet.getBatchId(), e.getMessage()); |
| | | logger.error("推送出错", e); |
| | | } |
| | | } |
| | | } else { |
| | |
| | | logger.error("任务为空,taskId-{},batchId-{}", dataSet.getTaskId(), dataSet.getBatchId()); |
| | | } |
| | | //删除消息 |
| | | logger.info("推送任务执行完成,taskId-{},batchId-{}", dataSet.getTaskId(), dataSet.getBatchId()); |
| | | CMQManager.getInstance().deleteMsg(result.getQueueName(), result.getReceiptHandle()); |
| | | pushExcuteResultManager.batchPushFinish(dataSet, platform); |
| | | logger.info("{}推送任务执行结束,taskId-{},batchId-{}", platform.name(), dataSet.getTaskId(), dataSet.getBatchId()); |
| | | } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | logger.error("推送出错:", e); |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | package com.ks.push.controller; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.ks.push.dto.mq.InvalidDeviceTokenInfo; |
| | | import com.ks.push.manager.BPushPlatformAppInfoManager; |
| | | import com.ks.push.manager.CMQManager; |
| | | import com.ks.push.pojo.DO.PushPlatform; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.ResponseBody; |
| | | import org.yeshi.utils.StringUtil; |
| | | import org.yeshi.utils.wx.WXUtil; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | /** |
| | | * @author Administrator |
| | | * @title: PushCallbackController |
| | | * @description: 各大手机推送平台的消息回执 |
| | | * @date 2021/9/15 12:17 |
| | | */ |
| | | @Controller |
| | | @RequestMapping("callback") |
| | | public class PushCallbackController { |
| | | Logger logger = LoggerFactory.getLogger(PushCallbackController.class); |
| | | |
| | | @Resource |
| | | private BPushPlatformAppInfoManager bPushPlatformAppInfoManager; |
| | | |
| | | |
| | | //回调接口详情:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/msg-receipt-guide-0000001050040176#ZH-CN_TOPIC_0000001087208860__p121151147184318 |
| | | @ResponseBody |
| | | @RequestMapping("hw") |
| | | public String hw(HttpServletRequest request) { |
| | | String content = WXUtil.getContent(request); |
| | | if (StringUtil.isNullOrEmpty(content)) { |
| | | return ""; |
| | | } |
| | | JSONObject json = JSONObject.parseObject(content); |
| | | JSONArray statuses = json.getJSONArray("statuses"); |
| | | for (int i = 0; i < statuses.size(); i++) { |
| | | JSONObject statuse = statuses.getJSONObject(i); |
| | | String appId = statuse.getString("appid"); |
| | | String bigTag = statuse.getString("biTag"); |
| | | String token = statuse.getString("token"); |
| | | String appCode = bPushPlatformAppInfoManager.selectAppCode(appId, PushPlatform.hw); |
| | | //0-成功 |
| | | //2-应用未安装 |
| | | //5-指定的Token在当前Android终端用户下不存在 |
| | | //6-通知栏消息不展示 |
| | | //10-非活跃设备消息,设备为非活跃设备(终端设备未接入网络达30天),消息不进行下发。 |
| | | //15-离线用户消息覆盖 |
| | | //27-在终端设备上目标应用进程不存在导致透传消息被缓存 |
| | | //102-消息频控丢弃 |
| | | //144-profileId不存在 |
| | | //201-消息发送管控 |
| | | int status = statuse.getInteger("status"); |
| | | if (status == 0) { |
| | | logger.debug("华为消息回执-推送成功:bigTag-{} token-{}", bigTag, token); |
| | | } else { |
| | | logger.debug("华为消息回执-推送失败:bigTag-{} token-{} status-{}", bigTag, token, status); |
| | | if (status == 2 || status == 5 || status == 10) { |
| | | //删除无效设备 |
| | | CMQManager.getInstance().addInvalidDevieToken(new InvalidDeviceTokenInfo(appCode, PushPlatform.hw, token)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | JSONObject data = new JSONObject(); |
| | | data.put("code", 0); |
| | | data.put("message", "success"); |
| | | return data.toJSONString(); |
| | | } |
| | | |
| | | |
| | | //回执消息的格式:https://dev.mi.com/console/doc/detail?pId=1278#_3_6 |
| | | @ResponseBody |
| | | @RequestMapping("xm") |
| | | public String xm(HttpServletRequest request) { |
| | | String content = WXUtil.getContent(request); |
| | | logger.debug("小米消息回执-{}", content); |
| | | JSONObject json = JSONObject.parseObject(content); |
| | | |
| | | for (String msgId : json.keySet()) { |
| | | JSONObject data = json.getJSONObject(msgId); |
| | | String appId = data.getString("param"); |
| | | String appCode = bPushPlatformAppInfoManager.selectAppCode(appId, PushPlatform.xm); |
| | | int type = data.getInteger("type"); |
| | | switch (type) { |
| | | //送达 |
| | | case 1: |
| | | break; |
| | | //点击 |
| | | case 2: |
| | | break; |
| | | //无法找到目标设备 |
| | | case 16: |
| | | String regIdStr = data.getString("targets"); |
| | | String[] regIds = regIdStr.split(","); |
| | | for (String rid : regIds) { |
| | | //删除无效设备 |
| | | CMQManager.getInstance().addInvalidDevieToken(new InvalidDeviceTokenInfo(appCode, PushPlatform.xm, rid)); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | JSONObject data = new JSONObject(); |
| | | data.put("code", 0); |
| | | data.put("message", "success"); |
| | | return ""; |
| | | } |
| | | |
| | | |
| | | @ResponseBody |
| | | @RequestMapping("oppo") |
| | | public String oppo(HttpServletRequest request) { |
| | | String content = WXUtil.getContent(request); |
| | | logger.debug("oppo消息回执-{}", content); |
| | | JSONObject data = new JSONObject(); |
| | | data.put("code", 0); |
| | | data.put("message", "success"); |
| | | return ""; |
| | | } |
| | | |
| | | } |
| | |
| | | import com.ks.push.vo.BPushTaskVO; |
| | | import net.sf.json.JSONArray; |
| | | import net.sf.json.JSONObject; |
| | | import org.springframework.data.domain.Sort; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.stereotype.Controller; |
| | |
| | | import javax.servlet.http.HttpSession; |
| | | import java.lang.reflect.Type; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | |
| | | query.appCode = appCode; |
| | | query.state = state; |
| | | query.messageTitle = key; |
| | | query.sortList= Arrays.asList(new Sort.Order[]{new Sort.Order(Sort.Direction.DESC,"createTime")}); |
| | | |
| | | |
| | | List<BPushTask> list = bPushTaskService.list(query, page, limit); |
| | |
| | | public void updateSelective(BPushDeviceToken bean) { |
| | | Query query = new Query(); |
| | | Update update = new Update(); |
| | | query.addCriteria(Criteria.where("id").is(bean.getId())); |
| | | query.addCriteria(Criteria.where("_id").is(bean.getId())); |
| | | if (bean.getAppCode() != null) { |
| | | update.set("appCode", bean.getAppCode()); |
| | | } |
| | |
| | | andList.add(Criteria.where("updateTime").lt(daoQuery.maxUpdateTime)); |
| | | } |
| | | |
| | | if (daoQuery.token != null) { |
| | | andList.add(Criteria.where("token").lt(daoQuery.token)); |
| | | } |
| | | |
| | | Criteria[] ands = new Criteria[andList.size()]; |
| | | andList.toArray(ands); |
| | | |
| | |
| | | public List<String> uidList; |
| | | public List<String> deviceIdList; |
| | | public List<String> brandNameList; |
| | | public String token; |
| | | public Date minUpdateTime; |
| | | public Date maxUpdateTime; |
| | | public Date minCreateTime; |
| | |
| | | import com.ks.push.pojo.DO.BPushTask; |
| | | import com.ks.lib.common.dao.MongodbBaseDao; |
| | | import com.ks.push.pojo.Query.BPushTaskQuery; |
| | | import org.springframework.data.domain.Sort; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.data.mongodb.core.query.Update; |
| | |
| | | Query query = getQuery(daoQuery); |
| | | query.skip(start); |
| | | query.limit(count); |
| | | if (daoQuery.sortList != null) { |
| | | query.with(Sort.by(daoQuery.sortList)); |
| | | } |
| | | return findList(query); |
| | | } |
| | | |
New file |
| | |
| | | package com.ks.push.dto.mq; |
| | | |
| | | import com.ks.push.pojo.DO.PushPlatform; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * @author Administrator |
| | | * @title: InvalidDeviceTokenInfo |
| | | * @description: 无效设备信息 |
| | | * @date 2021/9/17 11:26 |
| | | */ |
| | | public class InvalidDeviceTokenInfo implements Serializable { |
| | | |
| | | private String appCode; |
| | | private PushPlatform pushPlatform; |
| | | private String token; |
| | | private Date createTime; |
| | | |
| | | public InvalidDeviceTokenInfo() { |
| | | |
| | | } |
| | | |
| | | public InvalidDeviceTokenInfo(String appCode, PushPlatform pushPlatform, String token) { |
| | | this.appCode = appCode; |
| | | this.pushPlatform = pushPlatform; |
| | | this.token = token; |
| | | this.createTime = new Date(); |
| | | } |
| | | |
| | | public String getAppCode() { |
| | | return appCode; |
| | | } |
| | | |
| | | public void setAppCode(String appCode) { |
| | | this.appCode = appCode; |
| | | } |
| | | |
| | | public PushPlatform getPushPlatform() { |
| | | return pushPlatform; |
| | | } |
| | | |
| | | public void setPushPlatform(PushPlatform pushPlatform) { |
| | | this.pushPlatform = pushPlatform; |
| | | } |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public void setToken(String token) { |
| | | this.token = token; |
| | | } |
| | | |
| | | public Date getCreateTime() { |
| | | return createTime; |
| | | } |
| | | |
| | | public void setCreateTime(Date createTime) { |
| | | this.createTime = createTime; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | public String selectAppCode(String appId, PushPlatform pushPlatform) { |
| | | Query query = new Query(); |
| | | query.addCriteria(Criteria.where("pushAppInfo.appId").is(appId).and("platform").is(pushPlatform)); |
| | | BPushPlatformAppInfo appInfo = bPushPlatformAppInfoDao.findOne(query); |
| | | if (appInfo == null) { |
| | | return null; |
| | | } |
| | | return appInfo.getAppCode(); |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | |
| | | import com.google.gson.Gson; |
| | | import com.ks.push.dto.BPushDeviceDataSet; |
| | | import com.ks.push.dto.mq.InvalidDeviceTokenInfo; |
| | | import com.ks.push.pojo.DO.PushPlatform; |
| | | import com.qcloud.cmq.Message; |
| | | import org.slf4j.Logger; |
| | |
| | | */ |
| | | public static String PUSH_MZ = "bpush-mz"; |
| | | |
| | | /** |
| | | * 无效设备队列 |
| | | */ |
| | | public static String PUSH_TOKEN_INVALID = "bpush-token-invalid"; |
| | | |
| | | static { |
| | | cmqUtil = CMQUtil.getInstance(secretId, secretKey); |
| | | // 最大消息为1M |
| | |
| | | cmqUtil.createQueue(PUSH_OPPO); |
| | | cmqUtil.createQueue(PUSH_VIVO); |
| | | cmqUtil.createQueue(PUSH_MZ); |
| | | cmqUtil.createQueue(PUSH_TOKEN_INVALID); |
| | | logger.info("创建队列完毕"); |
| | | } |
| | | |
| | |
| | | return null; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 删除消息 |
| | | * |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 发送无效设备消息 |
| | | * |
| | | * @param info |
| | | */ |
| | | public void addInvalidDevieToken(InvalidDeviceTokenInfo info) { |
| | | if (info == null) { |
| | | return; |
| | | } |
| | | cmqUtil.sendMsg(PUSH_TOKEN_INVALID, new Gson().toJson(info)); |
| | | } |
| | | |
| | | /** |
| | | * 消费无效设备消息 |
| | | * |
| | | * @param count |
| | | */ |
| | | public List<MQMsgConsumeResult> consumeInvalidDeviceTokenQueue(int count) throws Exception { |
| | | List<Message> list = cmqUtil.recieveMsg(count, PUSH_TOKEN_INVALID); |
| | | if (list != null) { |
| | | List<MQMsgConsumeResult> resultList = new ArrayList<>(); |
| | | for (Message msg : list) { |
| | | String result = msg.msgBody; |
| | | InvalidDeviceTokenInfo tokenInfo = new Gson().fromJson(result, InvalidDeviceTokenInfo.class); |
| | | resultList.add(new MQMsgConsumeResult(tokenInfo, PUSH_TOKEN_INVALID, msg.receiptHandle)); |
| | | } |
| | | return resultList; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | |
| | | public static class MQMsgConsumeResult { |
| | | private String queueName; |
| | | private Object data; |
| | |
| | | return bPushDeviceTokenDao.count(getDaoQuery(appCode, platform, filter)); |
| | | } |
| | | |
| | | public List<BPushDeviceToken> list(String appCode, PushPlatform platform, String token, int page, int pageSize) { |
| | | BPushDeviceTokenDao.DaoQuery daoQuery = new BPushDeviceTokenDao.DaoQuery(); |
| | | daoQuery.appCode = appCode; |
| | | daoQuery.token = token; |
| | | daoQuery.type = platform; |
| | | return bPushDeviceTokenDao.list(daoQuery, (page - 1) * pageSize, pageSize); |
| | | } |
| | | |
| | | public void deleteByPrimaryKey(String id) { |
| | | bPushDeviceTokenDao.delete(id); |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | import com.ks.push.pojo.DO.BPushTask; |
| | | import com.ks.push.pojo.DO.BPushTaskExcuteResult; |
| | | import com.ks.push.pojo.DO.PushPlatform; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | |
| | | @Component |
| | | public class PushExcuteResultManager { |
| | | |
| | | private Logger logger = LoggerFactory.getLogger(PushExcuteResultManager.class); |
| | | |
| | | @Resource |
| | | private BPushTaskExcuteResultMapper bPushTaskExcuteResultMapper; |
| | | |
| | | |
| | | @Resource |
| | | private RedisTemplate<String, Object> redisTemplate; |
| | | private RedisTemplate<String, String> redisTemplate; |
| | | |
| | | @Resource |
| | | private BPushTaskDao bPushTaskDao; |
| | |
| | | result.setId(BPushTaskExcuteResult.createId(taskId, pushPlatform)); |
| | | //初始化 |
| | | bPushTaskExcuteResultMapper.insertSelective(result); |
| | | |
| | | String key = getRedisKey(taskId, pushPlatform); |
| | | redisTemplate.delete(key); |
| | | return result; |
| | |
| | | */ |
| | | public void batchPushFinish(BPushDeviceDataSet dataSet, PushPlatform pushPlatform) { |
| | | String key = getRedisKey(dataSet.getTaskId(), pushPlatform); |
| | | redisTemplate.opsForSet().remove(key, dataSet.getBatchId()); |
| | | Long size = redisTemplate.opsForSet().size(key); |
| | | redisTemplate.opsForSet().remove(key, dataSet.getBatchId()); |
| | | Long afterSize = redisTemplate.opsForSet().size(key); |
| | | logger.info("{}推送剩余数量 taskId-{} size-{} afterSize-{}", pushPlatform.name(), dataSet.getTaskId(), size + "", afterSize + ""); |
| | | //判断是否推送完成 |
| | | if (size == null || size == 0L) { |
| | | if (afterSize == null || afterSize == 0L) { |
| | | //已经推送完了 |
| | | String id = BPushTaskExcuteResult.createId(dataSet.getTaskId(), pushPlatform); |
| | | BPushTaskExcuteResult update = new BPushTaskExcuteResult(); |
| | |
| | | updateTask.setStateDesc("推送完成"); |
| | | updateTask.setUpdateTime(new Date()); |
| | | bPushTaskDao.updateSelective(updateTask); |
| | | logger.info("{}推送完成 taskId-{}", pushPlatform.name(), dataSet.getTaskId()); |
| | | } |
| | | } |
| | | } |
| | |
| | | private BPushPlatformAppInfoManager bPushPlatformAppInfoManager; |
| | | |
| | | @Resource |
| | | private RedisTemplate<String, Object> redisTemplate; |
| | | private PushExcuteResultManager pushExcuteResultManager; |
| | | |
| | | @Resource |
| | | private PushExcuteResultManager pushExcuteResultManager; |
| | | private RedisTemplate redisTemplate; |
| | | |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | String key = "task-" + taskId; |
| | | if (!redisTemplate.opsForValue().setIfAbsent(key, "1", 5 * 60, TimeUnit.SECONDS)) { |
| | | |
| | | Boolean s = redisTemplate.opsForValue().setIfAbsent(key, "1", 5 * 60, TimeUnit.SECONDS); |
| | | |
| | | if (s == null || !s) { |
| | | throw new BPushTaskException(BPushTaskException.CODE_BUSY, "服务器繁忙,请稍后再试"); |
| | | } |
| | | |
| | | |
| | | logger.info("开始启动推送#taskId:{}", task.getId()); |
| | | updateState(taskId, BPushTask.STATE_PUSHING, null); |
| | | boolean hasDevice = false; |
| | | try { |
| | | // 查询可推送的平台 |
| | | List<BPushPlatformAppInfo> list = bPushPlatformAppInfoManager.listByAppCode(task.getAppCode()); |
| | | |
| | | //先初始化推送结果数据数据 |
| | | List<BPushTaskExcuteResult> resultList = new ArrayList<>(); |
| | | Map<String, Long> resultCountMap = new HashMap<>(); |
| | | for (BPushPlatformAppInfo appInfo : list) { |
| | | long count = pushDeviceTokenManager.count(task.getAppCode(), appInfo.getPlatform(), task.getFilter()); |
| | | if (count > 0) { |
| | | hasDevice = true; |
| | | //初始化推送结果数据 |
| | | BPushTaskExcuteResult result = pushExcuteResultManager.initPushExcuteResult(taskId, appInfo.getPlatform(), count); |
| | | resultCountMap.put(result.getId(), count); |
| | | resultList.add(result); |
| | | } |
| | | // 查询可推送的平台 |
| | | List<BPushPlatformAppInfo> list = bPushPlatformAppInfoManager.listByAppCode(task.getAppCode()); |
| | | |
| | | //先初始化推送结果数据数据 |
| | | List<BPushTaskExcuteResult> resultList = new ArrayList<>(); |
| | | Map<String, Long> resultCountMap = new HashMap<>(); |
| | | for (BPushPlatformAppInfo appInfo : list) { |
| | | long count = pushDeviceTokenManager.count(task.getAppCode(), appInfo.getPlatform(), task.getFilter()); |
| | | if (count > 0) { |
| | | hasDevice = true; |
| | | //初始化推送结果数据 |
| | | BPushTaskExcuteResult result = pushExcuteResultManager.initPushExcuteResult(taskId, appInfo.getPlatform(), count); |
| | | resultCountMap.put(result.getId(), count); |
| | | resultList.add(result); |
| | | } |
| | | |
| | | |
| | | for (BPushTaskExcuteResult result : resultList) { |
| | | long count = resultCountMap.get(result.getId()); |
| | | int pageSize = 500; |
| | | int totalPage = (int) (count % pageSize == 0 ? count / pageSize : count / pageSize + 1); |
| | | long totalValidCount = 0L; |
| | | |
| | | //初始化批量推送的计数 |
| | | for (int page = 0; page < totalPage; page++) { |
| | | pushExcuteResultManager.startBatchPush(taskId, result.getPushPlatform(), page + ""); |
| | | } |
| | | |
| | | for (int page = 0; page < totalPage; page++) { |
| | | List<BPushDeviceToken> deviceTokenList = pushDeviceTokenManager.list(task.getAppCode(), result.getPushPlatform(), task.getFilter(), page + 1, pageSize); |
| | | |
| | | List<String> tokenList = new ArrayList<>(); |
| | | for (BPushDeviceToken deviceToken : deviceTokenList) { |
| | | //TODO 时间判断 |
| | | tokenList.add(deviceToken.getToken()); |
| | | } |
| | | totalValidCount += tokenList.size(); |
| | | BPushDeviceDataSet dataSet = new BPushDeviceDataSet(tokenList, page + "", taskId); |
| | | //最后一页 |
| | | if (page == totalPage - 1 && totalValidCount != count) { |
| | | //修改总数 |
| | | pushExcuteResultManager.setDeviceCount(result.getId(), totalValidCount); |
| | | } |
| | | CMQManager.getInstance().addToPushQueue(result.getPushPlatform(), dataSet); |
| | | } |
| | | logger.info("加入推送队列#任务Id:{}#平台:{}#推送数量:{}", task.getId(), result.getPushPlatform().name(), count); |
| | | } |
| | | } finally { |
| | | redisTemplate.delete(key); |
| | | } |
| | | |
| | | //没有可推送的设备 |
| | | |
| | | for (BPushTaskExcuteResult result : resultList) { |
| | | long count = resultCountMap.get(result.getId()); |
| | | int pageSize = 500; |
| | | int totalPage = (int) (count % pageSize == 0 ? count / pageSize : count / pageSize + 1); |
| | | long totalValidCount = 0L; |
| | | |
| | | //初始化批量推送的计数 |
| | | for (int page = 0; page < totalPage; page++) { |
| | | pushExcuteResultManager.startBatchPush(taskId, result.getPushPlatform(), page + ""); |
| | | } |
| | | |
| | | for (int page = 0; page < totalPage; page++) { |
| | | List<BPushDeviceToken> deviceTokenList = pushDeviceTokenManager.list(task.getAppCode(), result.getPushPlatform(), task.getFilter(), page + 1, pageSize); |
| | | |
| | | List<String> tokenList = new ArrayList<>(); |
| | | for (BPushDeviceToken deviceToken : deviceTokenList) { |
| | | //TODO 时间判断 |
| | | tokenList.add(deviceToken.getToken()); |
| | | } |
| | | totalValidCount += tokenList.size(); |
| | | BPushDeviceDataSet dataSet = new BPushDeviceDataSet(tokenList, page + "", taskId); |
| | | //最后一页 |
| | | if (page == totalPage - 1 && totalValidCount != count) { |
| | | //修改总数 |
| | | pushExcuteResultManager.setDeviceCount(result.getId(), totalValidCount); |
| | | } |
| | | CMQManager.getInstance().addToPushQueue(result.getPushPlatform(), dataSet); |
| | | } |
| | | logger.info("加入推送队列#任务Id:{}#平台:{}#推送数量:{}", task.getId(), result.getPushPlatform().name(), count); |
| | | } |
| | | |
| | | |
| | | if (!hasDevice) { |
| | | updateState(taskId, BPushTask.STATE_FINSIH, "没有满足条件的可推送设备"); |
| | | } |
| | | |
| | | //没有可推送的设备 |
| | | logger.info("启动推送结束#taskId:{}", task.getId()); |
| | | } |
| | | |
| | |
| | | @Override |
| | | public void unBindUid(String appCode, String deviceId) { |
| | | String id = BPushDeviceToken.createId(appCode, deviceId); |
| | | if (bPushDeviceTokenDao.get(id) == null) { |
| | | return; |
| | | } |
| | | Update update = new Update(); |
| | | update.set("uid", null); |
| | | update.set("updateTime", new Date()); |
| | | Query query = new Query(); |
| | | query.addCriteria(Criteria.where("_id").is(id)); |
| | | bPushDeviceTokenDao.update(query, update); |
| | |
| | | @Override |
| | | public void bindUid(String appCode, String deviceId, String uid) { |
| | | String id = BPushDeviceToken.createId(appCode, deviceId); |
| | | if (bPushDeviceTokenDao.get(id) == null) { |
| | | return; |
| | | } |
| | | Update update = new Update(); |
| | | update.set("uid", uid); |
| | | Query query = new Query(); |
New file |
| | |
| | | package com.ks.push.utils; |
| | | |
| | | /** |
| | | * @author Administrator |
| | | * @title: Constant |
| | | * @description: TODO |
| | | * @date 2021/9/17 10:58 |
| | | */ |
| | | public class Constant { |
| | | |
| | | //消息回执 |
| | | public final static String PUSH_CALLBACK_XM_URL = "https://cb.push.banliapp.com:444/callback/xm"; |
| | | public final static String PUSH_CALLBACK_OPPO_URL = "https://cb.push.banliapp.com:444/callback/oppo"; |
| | | public final static String PUSH_CALLBACK_VIVO_URL = "https://cb.push.banliapp.com:444/callback/vivo"; |
| | | |
| | | } |
| | |
| | | package com.ks.push.utils; |
| | | |
| | | import com.google.gson.Gson; |
| | | import com.huawei.push.util.push.*; |
| | | import com.ks.push.pojo.DO.BPushMessage; |
| | | import com.ks.push.pojo.DO.PushPlatform; |
| | | import org.yeshi.utils.push.*; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.yeshi.utils.StringUtil; |
| | | import org.yeshi.utils.push.entity.PushAppInfo; |
| | | import org.yeshi.utils.push.entity.PushMessage; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public class PushUtil { |
| | | |
| | | static Logger logger = LoggerFactory.getLogger(PushUtil.class); |
| | | |
| | | /** |
| | | * 推送通知 |
| | |
| | | * @param tokenList |
| | | * @throws Exception |
| | | */ |
| | | public static void pushNotifyCation(PushPlatform platform, PushAppInfo appInfo, BPushMessage pushMessage, List<String> tokenList) throws Exception { |
| | | public static void pushNotifyCation(PushPlatform platform, PushAppInfo appInfo, BPushMessage pushMessage, String identifyCode, List<String> tokenList) throws Exception { |
| | | if (appInfo == null) { |
| | | throw new Exception("应用参数为空"); |
| | | } |
| | |
| | | if (tokenList == null || tokenList.size() == 0) { |
| | | throw new Exception("token为空"); |
| | | } |
| | | PushMessage message = new PushMessage(pushMessage.getTitle(), pushMessage.getContent(), pushMessage.getAndroidActivity(), pushMessage.getAndroidActivityScheme(), pushMessage.getAndroidHostPath(), pushMessage.getExtras()); |
| | | |
| | | logger.info("{}推送应用信息:{}", platform.name(), new Gson().toJson(appInfo)); |
| | | logger.info("{}推送内容信息:{}", platform.name(), new Gson().toJson(pushMessage)); |
| | | logger.info("{}推送token信息:{}", platform.name(), new Gson().toJson(tokenList)); |
| | | |
| | | |
| | | Map<String, String> extras = null; |
| | | if (pushMessage.getExtras() != null) { |
| | | extras = new HashMap<>(); |
| | | for (Iterator<String> its = pushMessage.getExtras().keySet().iterator(); its.hasNext(); ) { |
| | | String key = its.next(); |
| | | String value = pushMessage.getExtras().get(key); |
| | | if (!StringUtil.isNullOrEmpty(key) && !StringUtil.isNullOrEmpty(value)) { |
| | | extras.put(key, value); |
| | | } |
| | | } |
| | | } |
| | | |
| | | PushMessage message = new PushMessage(pushMessage.getTitle(), pushMessage.getContent(), pushMessage.getAndroidActivity(), pushMessage.getAndroidActivityScheme(), pushMessage.getAndroidHostPath(), extras); |
| | | |
| | | if (platform == PushPlatform.xm) { |
| | | pushXM(appInfo, message, tokenList); |
| | | } else if (platform == PushPlatform.hw) { |
| | | pushHW(appInfo, message, tokenList); |
| | | pushHW(appInfo, message, identifyCode, tokenList); |
| | | } else if (platform == PushPlatform.oppo) { |
| | | pushOPPO(appInfo, message, tokenList); |
| | | } else if (platform == PushPlatform.vivo) { |
| | |
| | | * |
| | | * @param appInfo |
| | | * @param message |
| | | * @param bigTag |
| | | * @param tokenList |
| | | * @throws Exception |
| | | */ |
| | | private static void pushHW(PushAppInfo appInfo, PushMessage message, List<String> tokenList) throws Exception { |
| | | HuaWeiPushUtil.pushNotificationByTokens(appInfo, message, tokenList); |
| | | private static void pushHW(PushAppInfo appInfo, PushMessage message, String bigTag, List<String> tokenList) throws Exception { |
| | | HuaWeiPushUtil.pushNotificationByTokens(appInfo, message, bigTag, tokenList); |
| | | } |
| | | |
| | | /** |
| | |
| | | authentication-database: admin |
| | | redis: |
| | | host: 193.112.35.168 #193.112.34.40 |
| | | port: 6379 |
| | | port: 6380 |
| | | #Yeshi2016@ |
| | | password: 'crs-43yhgz0i:Yeshi2016@' |
| | | timeout: 5000ms |
| | | timeout: 5000 |
| | | database: 10 |
| | | lettuce: |
| | | pool: |
| | | max-active: 1024 |
| | | max-wait: 10000ms |
| | | max-idle: 200 |
| | | time-between-eviction-runs: 60000ms |
| | | min-idle: 8 |
| | | jedis: |
| | | pool: |
| | | max-active: 1024 |
| | | max-active: 200 #连接池最大连接数 |
| | | max-wait: 5000 #连接池最大阻塞等待时间 |
| | | max-idle: 50 #连接池中的最大空闲连接 |
| | | time-between-eviction-runs: 60000 #每隔多长时间运行一次空闲连接回收器(独立线程) |
| | | min-idle: 0 #连接池中的最小空闲连接 |
| | | shutdown-timeout: 5000 #连接关闭超时时间 |
| | | jedis: |
| | | pool: |
| | | max-total: 1024 |
| | | max-wait: 10000ms |
| | | max-idle: 200 |
| | | time-between-eviction-runs: 60000ms |
| | | test_on_borrow: true |
| | | min-idle: 8 |
| | | |
| | | |
| | |
| | | configuration: |
| | | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl |
| | | |
| | | xxl: |
| | | job: |
| | | accessToken: |
| | | executor: |
| | | appname: service-push |
| | | ip: |
| | | logpath: /data/applogs/xxl-job/jobhandler |
| | | logretentiondays: -1 |
| | | port: 9999 |
| | | admin: |
| | | addresses: http://1.14.235.17:9000/xxl-job-admin |
| | | |
| | | |
| | | dubbo: |
| | | application: |
| | | name: push-service |
| | |
| | | port: 6379 |
| | | #Yeshi2016@ |
| | | password: 'crs-43yhgz0i:Yeshi2016@' |
| | | timeout: 5000ms |
| | | timeout: 5000 |
| | | database: 10 |
| | | lettuce: |
| | | pool: |
| | | max-active: 1024 |
| | | max-wait: 10000ms |
| | | max-idle: 200 |
| | | time-between-eviction-runs: 60000ms |
| | | min-idle: 8 |
| | | max-active: 200 #连接池最大连接数 |
| | | max-wait: 5000 #连接池最大阻塞等待时间 |
| | | max-idle: 50 #连接池中的最大空闲连接 |
| | | time-between-eviction-runs: 60000 #每隔多长时间运行一次空闲连接回收器(独立线程) |
| | | min-idle: 5 #连接池中的最小空闲连接 |
| | | shutdown-timeout: 5000 #连接关闭超时时间 |
| | | jedis: |
| | | pool: |
| | | max-active: 1024 |
| | | max-total: 1024 |
| | | max-wait: 10000ms |
| | | max-idle: 200 |
| | | time-between-eviction-runs: 60000ms |
| | | test_on_borrow: true |
| | | min-idle: 8 |
| | | |
| | | |
New file |
| | |
| | | token_server = https://oauth-login.cloud.huawei.com/oauth2/v2/token |
| | | push_open_url = https://push-api.cloud.huawei.com |
| | |
| | | </filter> |
| | | </appender> |
| | | |
| | | <appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <file>${log.filePath}/debug.log</file> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <fileNamePattern>${log.filePath}/debug/debug.log.gz.%d{yyyy-MM-dd}</fileNamePattern> |
| | | <maxHistory>${log.maxHistory}</maxHistory> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>${log.pattern}</pattern> |
| | | </encoder> |
| | | <filter class="ch.qos.logback.classic.filter.LevelFilter"> |
| | | <level>DEBUG</level> |
| | | <onMatch>ACCEPT</onMatch> |
| | | <onMismatch>DENY</onMismatch> |
| | | </filter> |
| | | </appender> |
| | | |
| | | |
| | | <appender name="redisAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <file>${log.filePath}/redis.log</file> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <fileNamePattern>${log.filePath}/redis/redis.log.gz.%d{yyyy-MM-dd}</fileNamePattern> |
| | | <maxHistory>${log.maxHistory}</maxHistory> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>${log.pattern}</pattern> |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <!--name表示为哪一个logger指定层级和输出的方式 |
| | | additivity表示叠加祖先的输出方式(默认为true,会叠加),所以com.lxc.o2o以及其子类都会输出在控制台中,因为这个logger继承了root中的appender |
| | | level表示级别大于等于${log.level}的信息才会输出,输出方式为配置的appender, |
| | |
| | | <logger name="io.seata" level="ERROR"></logger> |
| | | <logger name="System.out" level="INFO"></logger> |
| | | |
| | | <logger name="org.springframework.data.redis" level="DEBUG"> |
| | | <appender-ref ref="redisAppender"></appender-ref> |
| | | </logger> |
| | | |
| | | <logger name="io.lettuce.core" level="DEBUG"> |
| | | <appender-ref ref="redisAppender"></appender-ref> |
| | | </logger> |
| | | |
| | | |
| | | <!-- 一切logger都会继承自root,root默认的层级level为debug --> |
| | | <root level="INFO"> |
| | |
| | | <appender-ref ref="STDOUT"></appender-ref> |
| | | <appender-ref ref="errorAppender"></appender-ref> |
| | | <appender-ref ref="infoAppender"></appender-ref> |
| | | <appender-ref ref="debugAppender"></appender-ref> |
| | | </root> |
| | | </configuration> |
| | |
| | | <html class="x-admin-sm"> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>金币管理系统</title> |
| | | <title>推送管理系统</title> |
| | | <meta name="renderer" content="webkit|ie-comp|ie-stand"> |
| | | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
| | | <meta name="viewport" |
| | |
| | | <!-- 顶部开始 --> |
| | | <div class="container"> |
| | | <div class="logo"> |
| | | <a href="./index.html">金币管理系统</a></div> |
| | | <a href="./index.html">推送系统</a></div> |
| | | <div class="left_open"> |
| | | <a><i title="展开左侧栏" class="iconfont"></i></a> |
| | | </div> |
| | |
| | | |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>金币管理系统</title> |
| | | <title>推送管理系统</title> |
| | | <meta name="renderer" content="webkit"> |
| | | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
| | | <meta name="viewport" |
| | |
| | | |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>金币管理系统</title> |
| | | <title>推送管理系统</title> |
| | | <meta name="renderer" content="webkit"> |
| | | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
| | | <meta name="viewport" |