Commit 39dff818 by lanpingxiong

新增华为推送

parent 1fa24633
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
/src/main/resources/rebel.xml
# Getting Started
### Reference Documentation
For further reference, please consider the following sections:
* [Spring Security](https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#boot-features-security)
* [Spring Boot Actuator](https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#production-ready)
* [Spring Boot Admin (Client)](https://codecentric.github.io/spring-boot-admin/current/#getting-started)
* [Spring Boot Admin (Server)](https://codecentric.github.io/spring-boot-admin/current/#getting-started)
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2019-2029 geekidea(https://github.com/geekidea)
~
~ 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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.geekidea.springbootplus</groupId>
<artifactId>parent</artifactId>
<version>2.0</version>
</parent>
<artifactId>admin</artifactId>
<name>admin</name>
<description>Spring Boot Admin Server</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin.version}</version>
<exclusions>
<exclusion>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-cloud</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2019-2029 geekidea(https://github.com/geekidea)
*
* 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 io.geekidea.springbootplus.admin;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Spring Boot Admin 启动类
*
* @author geekidea
* @date 2020/3/20
**/
@Slf4j
@Configuration
@EnableAutoConfiguration
@EnableAdminServer
@SpringBootApplication
public class SpringBootPlusAdminApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusAdminApplication.class, args);
ConfigurableEnvironment environment = context.getEnvironment();
String serverPort = environment.getProperty("server.port");
log.info("SpringBootAdmin: http://localhost:" + serverPort);
}
}
/*
* Copyright 2019-2029 geekidea(https://github.com/geekidea)
*
* 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 io.geekidea.springbootplus.admin.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* WebMvc配置
*
* @author geekidea
* @date 2020/3/19
*/
@Configuration
public class AdminWebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 设置项目静态资源访问
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}
/*
* Copyright 2019-2029 geekidea(https://github.com/geekidea)
*
* 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 io.geekidea.springbootplus.admin.config;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import java.util.UUID;
/**
* Spring Boot Admin Security配置
* https://codecentric.github.io/spring-boot-admin/current/#_securing_spring_boot_admin_server
*
* @author geekidea
* @date 2020/3/20
*/
@Configuration(proxyBeanMethods = false)
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final AdminServerProperties adminServer;
@Value("${spring-boot-plus.admin.username}")
private String username;
@Value("${spring-boot-plus.admin.password}")
private String password;
public SecuritySecureConfig(AdminServerProperties adminServer) {
this.adminServer = adminServer;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(this.adminServer.path("/"));
http.authorizeRequests(
(authorizeRequests) -> authorizeRequests
.antMatchers(this.adminServer.path("/assets/**")).permitAll()
.antMatchers(this.adminServer.path("/static/**")).permitAll()
.antMatchers(this.adminServer.path("/login")).permitAll()
.anyRequest().authenticated()
).formLogin(
(formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler).and()
).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults())
.csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
new AntPathRequestMatcher(this.adminServer.path("/instances"),
HttpMethod.POST.toString()),
new AntPathRequestMatcher(this.adminServer.path("/instances/*"),
HttpMethod.DELETE.toString()),
new AntPathRequestMatcher(this.adminServer.path("/actuator/**"))
))
.rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(username).password("{noop}" + password).roles("USER");
}
}
\ No newline at end of file
server:
port: 8000
# Spring Boot Admin Server配置
spring:
boot:
admin:
monitor:
period: 100000
status-lifetime: 100000
connect-timeout: 100000
read-timeout: 100000
ui:
external-views:
- label: "🚀"
url: https://springboot.plus
order: 2000
# Spring Boot Admin 登录账号密码
spring-boot-plus:
admin:
username: admin
password: admin
package io.geekidea.springbootplus.config;
import com.wecloud.im.push.huawei.messaging.HuaweiApp;
import com.wecloud.im.push.huawei.util.InitAppUtils;
import com.wecloud.im.service.HuaweiPushServiceImpl;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties("upay.huawei")
public class HuaweiConfiguration {
private String appId;
private String appSecret;
private String tokenServer;
private String pushOpenUrl;
@Bean(destroyMethod = "delete")
HuaweiApp huaweiApp(){
return InitAppUtils.initializeApp(appId,appSecret,tokenServer,pushOpenUrl);
}
@Bean
HuaweiPushServiceImpl huaweiPushServiceImpl(HuaweiApp app){
return new HuaweiPushServiceImpl(app);
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getTokenServer() {
return tokenServer;
}
public void setTokenServer(String tokenServer) {
this.tokenServer = tokenServer;
}
public String getPushOpenUrl() {
return pushOpenUrl;
}
public void setPushOpenUrl(String pushOpenUrl) {
this.pushOpenUrl = pushOpenUrl;
}
}
......@@ -23,7 +23,7 @@ public class ImClientDeviceInfoAdd extends BaseEntity {
@ApiModelProperty("设备不想收到推送提醒, 1想, 0不想")
private Integer valid;
@ApiModelProperty("设备类型1:ios; 2:android; 3:web")
@ApiModelProperty("设备类型1:ios; 2:android; 3:web; 4:huawei")
private Integer deviceType;
@ApiModelProperty("设备推送token")
......
/*
* 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.wecloud.im.push.huawei.android;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.message.Notification;
import com.wecloud.im.push.huawei.model.Importance;
import com.wecloud.im.push.huawei.model.Visibility;
import com.wecloud.im.push.huawei.util.CollectionUtils;
import com.wecloud.im.push.huawei.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;
@JSONField(name = "profile_id")
private String profileId;
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;
}
this.profileId = builder.profileId;
}
/**
* 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 == 3;
ValidatorUtils.checkArgument(isTrue, "style should be one of 0:default, 1: big text, 3: Inbox");
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();
}
}
if (this.profileId != null) {
ValidatorUtils.checkArgument(this.profileId.length() > 64, "profileId length cannot exceed 64 characters");
}
}
/**
* 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;
}
public String getProfileId() { return profileId; }
/**
* 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 String profileId;
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);
}
public Builder setProfileId(String profileId) {
this.profileId = profileId;
return this;
}
}
}
/*
* 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.wecloud.im.push.huawei.android;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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 = 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);
}
}
}
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2029. All rights reserved.
*/
package com.wecloud.im.push.huawei.android;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.android;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.android;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.android;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.apns;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.util.CollectionUtils;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.apns;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.apns;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.util.ValidatorUtils;
public class ApnsHmsOptions {
private static final int TEST_USER = 1;
private static final int FORMAL_USER = 2;
private static final int VOIP_USER = 3;
@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);
}
}
}
/*
* 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.wecloud.im.push.huawei.apns;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.exception;
import com.google.common.base.Strings;
import com.wecloud.im.push.huawei.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");
}
}
/*
* 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.wecloud.im.push.huawei.exception;
import com.google.common.base.Strings;
import com.wecloud.im.push.huawei.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;
}
}
/*
* 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.wecloud.im.push.huawei.message;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.android.AndroidNotification;
import com.wecloud.im.push.huawei.model.Urgency;
import com.wecloud.im.push.huawei.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;
@JSONField(name = "receipt_id")
private String receiptId;
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;
this.receiptId = builder.receiptId;
}
/**
* 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;
}
public String getReceiptId() { return receiptId; }
/**
* 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 String receiptId;
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);
}
public Builder setReceiptId(String receiptId) {
this.receiptId = receiptId;
return this;
}
}
}
/*
* 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.wecloud.im.push.huawei.message;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.apns.ApnsHeaders;
import com.wecloud.im.push.huawei.apns.ApnsHmsOptions;
import com.wecloud.im.push.huawei.apns.Aps;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.message;
import com.alibaba.fastjson.annotation.JSONField;
import com.google.common.base.Strings;
import com.google.common.primitives.Booleans;
import com.wecloud.im.push.huawei.util.CollectionUtils;
import com.wecloud.im.push.huawei.util.ValidatorUtils;
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");
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);
}
}
}
/*
* 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.wecloud.im.push.huawei.message;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.message;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.message;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.webpush.WebHmsOptions;
import com.wecloud.im.push.huawei.webpush.WebNotification;
import com.wecloud.im.push.huawei.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);
}
}
}
/* 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.wecloud.im.push.huawei.messaging;
import com.google.common.collect.ImmutableList;
import com.wecloud.im.push.huawei.util.ValidatorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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();
}
}
}
/*
* 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.wecloud.im.push.huawei.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.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 String PUSH_AT_URL = ResourceBundle.getBundle("url").getString("token_server");
private String pushAtUrl;
private String appId;
private String appSecret;
private String pushOpenUrl;
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;
this.pushAtUrl=builder.tokenServer;
this.pushOpenUrl=builder.pushOpenUrl;
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(pushAtUrl);
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;
}
public String getPushOpenUrl() {
return pushOpenUrl;
}
/**
* Builder for constructing {@link HuaweiCredential}.
*/
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String appId;
private String appSecret;
private String tokenServer;
private String pushOpenUrl;
private CloseableHttpClient httpClient;
private Builder() {
}
public Builder setAppId(String appId) {
this.appId = appId;
return this;
}
public Builder setTokenServer(String tokenServer) {
this.tokenServer = tokenServer;
return this;
}
public Builder setPushOpenUrl(String pushOpenUrl) {
this.pushOpenUrl = pushOpenUrl;
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);
}
}
}
/*
* 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.wecloud.im.push.huawei.messaging;
import com.wecloud.im.push.huawei.exception.HuaweiMesssagingException;
import com.wecloud.im.push.huawei.message.Message;
import com.wecloud.im.push.huawei.message.TopicMessage;
import com.wecloud.im.push.huawei.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;
}
/*
* 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.wecloud.im.push.huawei.messaging;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wecloud.im.push.huawei.message.Message;
import com.wecloud.im.push.huawei.message.TopicMessage;
import com.wecloud.im.push.huawei.model.TopicOperation;
import com.wecloud.im.push.huawei.reponse.SendResponse;
import com.wecloud.im.push.huawei.reponse.TopicListResponse;
import com.wecloud.im.push.huawei.reponse.TopicSendResponse;
import com.wecloud.im.push.huawei.util.ValidatorUtils;
import com.wecloud.im.push.huawei.exception.HuaweiMesssagingException;
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
public class HuaweiMessageClientImpl implements HuaweiMessageClient {
// private static final String PUSH_URL = ResourceBundle.getBundle("url").getString("push_open_url");
private String pushUrl;
private final String HcmPushUrl;
private String hcmTopicUrl;
private String hcmGroupUrl;
private String hcmTokenUrl;
private final CloseableHttpClient httpClient;
private HuaweiMessageClientImpl(Builder builder) {
this.pushUrl=builder.pushOpenUrl;
this.HcmPushUrl = MessageFormat.format(pushUrl + "/v1/{0}/messages:send", builder.appId);
this.hcmTopicUrl = MessageFormat.format(pushUrl + "/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 {
String hcmTopicUrlTemp = MessageFormat.format(this.hcmTopicUrl, "", operation);
HttpPost httpPost = new HttpPost(hcmTopicUrlTemp);
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);
String pushOpenUrl = ImplHuaweiTrampolines.getPushOpenUrl(app);
return HuaweiMessageClientImpl.builder()
.setAppId(appId)
.setPushOpenUrl(pushOpenUrl)
.setHttpClient(app.getOption().getHttpClient())
.build();
}
static Builder builder() {
return new Builder();
}
static final class Builder {
private String appId;
private String pushOpenUrl;
private CloseableHttpClient httpClient;
private Builder() {
}
public Builder setAppId(String appId) {
this.appId = appId;
return this;
}
public Builder setPushOpenUrl(String pushOpenUrl) {
this.pushOpenUrl = pushOpenUrl;
return this;
}
public Builder setHttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient;
return this;
}
public HuaweiMessageClientImpl build() {
return new HuaweiMessageClientImpl(this);
}
}
}
/*
* 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.wecloud.im.push.huawei.messaging;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.wecloud.im.push.huawei.exception.HuaweiMesssagingException;
import com.wecloud.im.push.huawei.message.Message;
import com.wecloud.im.push.huawei.message.TopicMessage;
import com.wecloud.im.push.huawei.model.TopicOperation;
import com.wecloud.im.push.huawei.reponse.SendResponse;
import com.wecloud.im.push.huawei.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 HuaweiMessaging}
* by a instance of {@link com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.messaging;
import com.wecloud.im.push.huawei.util.IgnoreSSLUtils;
import com.wecloud.im.push.huawei.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(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);
}
}
}
/* 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.wecloud.im.push.huawei.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();
}
}
/*
* 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.wecloud.im.push.huawei.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();
}
/* 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.wecloud.im.push.huawei.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();
}
}
}
package com.wecloud.im.push.huawei.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 String getPushOpenUrl(HuaweiApp app) {
return app.getOption().getCredential().getPushOpenUrl();
}
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;
}
}
/* 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.wecloud.im.push.huawei.messaging;
import com.wecloud.im.push.huawei.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;
}
}
}
/* 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.wecloud.im.push.huawei.messaging;
import com.wecloud.im.push.huawei.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");
}
}
/*
* 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.wecloud.im.push.huawei.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;
}
}
/*
* 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.wecloud.im.push.huawei.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;
}
}
/*
* 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.wecloud.im.push.huawei.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;
}
}
/*
* 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.wecloud.im.push.huawei.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;
}
}
/*
* 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.wecloud.im.push.huawei.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);
}
}
/*
* 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.wecloud.im.push.huawei.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);
}
}
/*
* 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.wecloud.im.push.huawei.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);
}
}
/*
* 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.wecloud.im.push.huawei.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();
}
}
/*
* 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.wecloud.im.push.huawei.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();
}
}
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2024. All rights reserved.
*/
package com.wecloud.im.push.huawei.util;
import com.wecloud.im.push.huawei.messaging.HuaweiApp;
import com.wecloud.im.push.huawei.messaging.HuaweiCredential;
import com.wecloud.im.push.huawei.messaging.HuaweiOption;
public class InitAppUtils {
/**
* @return HuaweiApp
*/
// public static HuaweiApp initializeApp() {
// String appId = ResourceBundle.getBundle("url").getString("appid");
// String appSecret = ResourceBundle.getBundle("url").getString("appsecret");
// // Create HuaweiCredential
// // This appId and appSecret come from Huawei Developer Alliance
// return initializeApp(appId, appSecret);
// }
public static HuaweiApp initializeApp(String appId, String appSecret,String tokenServer,String pushOpenUrl) {
HuaweiCredential credential = HuaweiCredential.builder()
.setAppId(appId)
.setAppSecret(appSecret)
.setTokenServer(tokenServer)
.setPushOpenUrl(pushOpenUrl)
.build();
// Create HuaweiOption
HuaweiOption option = HuaweiOption.builder()
.setCredential(credential)
.build();
// Initialize HuaweiApp
// return HuaweiApp.initializeApp(option);
return HuaweiApp.getInstance(option);
}
}
/*
* 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.wecloud.im.push.huawei.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));
}
}
}
/*
* 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.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.webpush;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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);
}
}
}
/*
* 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.wecloud.im.push.huawei.webpush;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.util.CollectionUtils;
import com.wecloud.im.push.huawei.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<Integer> vibrate = new ArrayList<>();
@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<Integer> 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<Integer> vibrate = new ArrayList<>();
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<Integer> vibrate) {
this.vibrate.addAll(vibrate);
return this;
}
public Builder addVibrate(Integer 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);
}
}
}
/*
* 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.wecloud.im.push.huawei.webpush;
import com.alibaba.fastjson.annotation.JSONField;
import com.wecloud.im.push.huawei.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.wecloud.im.service;
import com.alibaba.fastjson.JSONObject;
import com.wecloud.im.push.huawei.android.AndroidNotification;
import com.wecloud.im.push.huawei.android.ClickAction;
import com.wecloud.im.push.huawei.message.AndroidConfig;
import com.wecloud.im.push.huawei.message.Message;
import com.wecloud.im.push.huawei.messaging.HuaweiApp;
import com.wecloud.im.push.huawei.messaging.HuaweiMessaging;
import com.wecloud.im.push.huawei.model.Urgency;
import com.wecloud.im.push.huawei.reponse.SendResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
@Slf4j
public class HuaweiPushServiceImpl implements IHuaweiPushService {
private HuaweiMessaging huaweiMessaging;
public HuaweiPushServiceImpl(HuaweiApp app) {
huaweiMessaging = HuaweiMessaging.getInstance(app);
}
@Override
public void singlePush(String token, String title, String body, HashMap data) throws Exception {
ClickAction clickAction = ClickAction.builder().setType(3).build();
AndroidNotification androidNotification = AndroidNotification.builder()
.setTitle(title)
.setBody(body)
.setClickAction(clickAction)
.build();
AndroidConfig androidConfig = AndroidConfig.builder()
.setCollapseKey(-1)
.setUrgency(Urgency.NORMAL.getValue())
.setNotification(androidNotification)
.build();
Message message = Message.builder()
.setAndroidConfig(androidConfig)
.setData(JSONObject.toJSONString(data))
.addToken(token)
.build();
SendResponse sendResponse = huaweiMessaging.sendMessage(message);
log.info("Huawei singlePush: " + JSONObject.toJSONString(sendResponse));
if (sendResponse == null) {
log.error("Huawei response is null");
return;
}
if (!"80000000".equals(sendResponse.getCode())) {
log.error("Huawei business error code ={} msg={}", sendResponse.getCode(), sendResponse.getMsg());
}
}
JSONObject getPushData(Integer notificationId, String title, String body) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("pushType", "system");
if (notificationId != null) {
jsonObject.put("notificationId", notificationId + "");
}
if (StringUtils.isNotBlank(title)) {
jsonObject.put("title", title);
}
if (StringUtils.isNotBlank(body)) {
jsonObject.put("body", body);
}
return jsonObject;
}
}
package com.wecloud.im.service;
import com.google.firebase.messaging.FirebaseMessagingException;
import java.util.HashMap;
import java.util.List;
public interface IHuaweiPushService {
/**
* 发送单个设备
*
* @param token 特定设备token
* @param title 通知标题
* @param body 通知内容
*/
void singlePush(String token, String title, String body, HashMap data) throws Exception;
}
......@@ -8,6 +8,7 @@ import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImIosApns;
import com.wecloud.im.push.PushUtils;
import com.wecloud.im.service.HuaweiPushServiceImpl;
import com.wecloud.im.service.ImInboxService;
import com.wecloud.im.service.ImIosApnsService;
import com.wecloud.im.ws.model.request.PushModel;
......@@ -17,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
......@@ -37,10 +39,10 @@ public class PushTask {
@Autowired
private ImIosApnsService imIosApnsService;
@Autowired
private ImInboxService imInboxService;
@Resource
private HuaweiPushServiceImpl huaweiPushService;
/**
* 谷歌推送地址
......@@ -70,17 +72,16 @@ public class PushTask {
@Async
public void push(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
log.info("push:" + imClientReceiver.getClientId());
if (pushModel == null) {
pushModel = new PushModel();
pushModel.setTitle(PUSH_TITLE);
pushModel.setSubTitle(PUSH_BODY);
pushModel.setData(new HashMap<>(1));
}
// 校验参数
if (imClientReceiver.getValid() == null || imClientReceiver.getDeviceToken() == null || imClientReceiver.getDeviceType() == null) {
if (imClientReceiver.getValid() == null
|| imClientReceiver.getDeviceToken() == null
|| imClientReceiver.getDeviceType() == null) {
log.info("push参数错误");
return;
}
......@@ -88,17 +89,15 @@ public class PushTask {
if (imClientReceiver.getValid() == 0) {
return;
}
// 设备类型1:ios; 2:android
if (imClientReceiver.getDeviceType() == 1) {
ios(pushModel, imClientReceiver, imApplication);
} else if (imClientReceiver.getDeviceType() == 4) {
huawei(pushModel, imClientReceiver);
} else {
android(pushModel, imClientReceiver, imApplication);
}
}
/**
* 异步系统推送
*
......@@ -107,11 +106,8 @@ public class PushTask {
@Async
public void push(HashMap<String, Object> pushMap, ImClient imClientReceiver, ImApplication imApplication) {
log.info("push:" + imClientReceiver.getClientId());
PushModel pushModel = getPushModel(pushMap);
this.push(pushModel, imClientReceiver, imApplication);
}
private PushModel getPushModel(HashMap<String, Object> pushMap) {
......@@ -123,7 +119,6 @@ public class PushTask {
} else {
pushModel.setTitle((String) pushMap.get(title));
pushModel.setSubTitle((String) pushMap.get(subTitle));
// 自定义推送内容
// try {
HashMap hashMap = (HashMap) pushMap.get(DATA);
......@@ -133,10 +128,22 @@ public class PushTask {
// pushModel.setData(new HashMap<>(1));
// }
}
return pushModel;
}
private void huawei(PushModel pushModel, ImClient imClientReceiver) {
try {
huaweiPushService.singlePush(
imClientReceiver.getDeviceToken(),
pushModel.getTitle(),
pushModel.getSubTitle(),
pushModel.getData()
);
} catch (Exception e) {
log.error("huawei 推送失败", e);
}
}
private void android(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
if (imApplication.getAndroidPushChannel() == null) {
......
......@@ -45,3 +45,10 @@ mybatis-plus:
load-blance:
# 服务器运营商local,aws,huawei
server-type: local
wecloudIm:
huawei:
app-id: 106973311
app-secret: 0e2f60191d42e9d4d40930c8a4d485d8ade743a244ffc9c9315a8e09b8c85702
token-server: https://oauth-login.cloud.huawei.com/oauth2/v3/token
push-open-url: https://push-api.cloud.huawei.com
......@@ -71,3 +71,10 @@ knife4j:
load-blance:
# 服务器运营商local,aws,huawei
server-type: aws
wecloudIm:
huawei:
app-id: 106934891
app-secret: d263f7b3f0dbd47b33f0efb31a8231675652c822977a615e2034b589330e2890
token-server: https://oauth-login.cloud.huawei.com/oauth2/v3/token
push-open-url: https://push-api.cloud.huawei.com
......@@ -60,3 +60,10 @@ mybatis-plus:
load-blance:
# 服务器运营商local,aws,huawei
server-type: aws
wecloudIm:
huawei:
app-id: 106973311
app-secret: 0e2f60191d42e9d4d40930c8a4d485d8ade743a244ffc9c9315a8e09b8c85702
token-server: https://oauth-login.cloud.huawei.com/oauth2/v3/token
push-open-url: https://push-api.cloud.huawei.com
......@@ -24,3 +24,10 @@ spring:
password:
port:
wecloudIm:
huawei:
app-id: 106973311
app-secret: 0e2f60191d42e9d4d40930c8a4d485d8ade743a244ffc9c9315a8e09b8c85702
token-server: https://oauth-login.cloud.huawei.com/oauth2/v3/token
push-open-url: https://push-api.cloud.huawei.com
-- 添加华为推送
-- 添加华为推送
-- device_type 修改描述 设备类型1:ios; 2:android; 3:web; 4:huawei
/target/
/classes
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
.DS_Store
*.log
logs
*.rdb
# scheduled 项目任务调度模块
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.geekidea.springbootplus</groupId>
<artifactId>parent</artifactId>
<version>2.0</version>
</parent>
<artifactId>scheduled</artifactId>
<name>scheduled</name>
<description>任务调度JOB模块</description>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>io.geekidea.springbootplus</groupId>-->
<!-- <artifactId>example</artifactId>-->
<!-- </dependency>-->
</dependencies>
</project>
/*
* Copyright 2019-2029 geekidea(https://github.com/geekidea)
*
* 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 io.geekidea.springbootplus.scheduled;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author geekidea
* @date 2020/3/16
**/
@Slf4j
@Component
public class HelloScheduled {
/**
* 每小时执行一次
*/
@Scheduled(cron = "0 0 0/1 * * ? ")
public void hello() throws Exception {
log.info("HelloScheduled...");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment