TeslaCN commented on a change in pull request #1473: URL: https://github.com/apache/shardingsphere-elasticjob/pull/1473#discussion_r491806811
########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/pom.xml ########## @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You 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="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + 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> + <artifactId>elasticjob-error-handler</artifactId> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <version>3.0.0-beta-SNAPSHOT</version> + </parent> + + <artifactId>elasticjob-error-handler-dingtalk</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <artifactId>elasticjob-error-handler-general</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>log4j-over-slf4j</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.5.12</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>4.4.13</version> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <artifactId>elasticjob-restful</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> Review comment: Need a blank line. ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/impl/fixture/DingtalkInternalController.java ########## @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl.fixture; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; +import org.apache.shardingsphere.elasticjob.restful.Http; +import org.apache.shardingsphere.elasticjob.restful.RestfulController; +import org.apache.shardingsphere.elasticjob.restful.annotation.Mapping; +import org.apache.shardingsphere.elasticjob.restful.annotation.Param; +import org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource; +import org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Map; + +@Slf4j +public final class DingtalkInternalController implements RestfulController { + + private static final String ACCESS_TOKEN = "42eead064e81ce81fc6af2c107fbe10a4339a3d40a7db8abf5b34d8261527a3f"; + + private static final String KEYWORD = "keyword"; + + private static final String SECRET = "SEC0b0a6b13b6823b95737dd83491c23adee5d8a7a649899a12217e038eddc84ff4"; + + Review comment: Remove redundant line. ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/impl/fixture/DingtalkInternalController.java ########## @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl.fixture; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; +import org.apache.shardingsphere.elasticjob.restful.Http; +import org.apache.shardingsphere.elasticjob.restful.RestfulController; +import org.apache.shardingsphere.elasticjob.restful.annotation.Mapping; +import org.apache.shardingsphere.elasticjob.restful.annotation.Param; +import org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource; +import org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Map; + +@Slf4j +public final class DingtalkInternalController implements RestfulController { + + private static final String ACCESS_TOKEN = "42eead064e81ce81fc6af2c107fbe10a4339a3d40a7db8abf5b34d8261527a3f"; + + private static final String KEYWORD = "keyword"; + + private static final String SECRET = "SEC0b0a6b13b6823b95737dd83491c23adee5d8a7a649899a12217e038eddc84ff4"; + + Review comment: Remove redundant blank line. ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/pom.xml ########## @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You 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="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + 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> + <artifactId>elasticjob-error-handler</artifactId> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <version>3.0.0-beta-SNAPSHOT</version> + </parent> + + <artifactId>elasticjob-error-handler-dingtalk</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <artifactId>elasticjob-error-handler-general</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> Review comment: "Provided" scope is recommended. ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/pom.xml ########## @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You 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="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + 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> + <artifactId>elasticjob-error-handler</artifactId> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <version>3.0.0-beta-SNAPSHOT</version> + </parent> + + <artifactId>elasticjob-error-handler-dingtalk</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.shardingsphere.elasticjob</groupId> + <artifactId>elasticjob-error-handler-general</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>log4j-over-slf4j</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + </dependency> Review comment: Are they optional? ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/impl/DingtalkJobErrorHandler.java ########## @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.config.RequestConfig; +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.apache.shardingsphere.elasticjob.error.handler.JobErrorHandler; +import org.apache.shardingsphere.elasticjob.error.handler.config.DingtalkConfiguration; +import org.apache.shardingsphere.elasticjob.error.handler.env.DingtalkEnvironment; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Collections; + +/** + * Job error handler for dingtalk error message. + */ +@Slf4j +public final class DingtalkJobErrorHandler implements JobErrorHandler { + + @Setter + private DingtalkConfiguration dingtalkConfiguration; + + private CloseableHttpClient httpclient = HttpClients.createDefault(); + + public DingtalkJobErrorHandler() { + registerShutdownHook(); + } + + @SneakyThrows + @Override + public void handleException(final String jobName, final Throwable cause) { + if (null == dingtalkConfiguration) { + dingtalkConfiguration = DingtalkEnvironment.getInstance().getDingtalkConfiguration(); + } + HttpPost httpPost = new HttpPost(getUrl()); + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(dingtalkConfiguration.getConnectTimeout()) + .setSocketTimeout(dingtalkConfiguration.getReadTimeout()).build(); + httpPost.setConfig(requestConfig); + String paramJson = getParamJson(getMsg(jobName, cause)); + StringEntity entity = new StringEntity(paramJson, StandardCharsets.UTF_8.name()); + entity.setContentEncoding(StandardCharsets.UTF_8.name()); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + CloseableHttpResponse response = httpclient.execute(httpPost); + try { + int status = response.getStatusLine().getStatusCode(); + if (HttpURLConnection.HTTP_OK == status) { + JsonObject resp = GsonFactory.getGson().fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class); + if (!"0".equals(resp.get("errcode").getAsString())) { + log.error("An exception has occurred in Job '{}', But failed to send alert by Dingtalk because of: {}", jobName, resp.get("errmsg").getAsString(), cause); + } else { + log.error("An exception has occurred in Job '{}', Notification to Dingtalk was successful.", jobName, cause); + } + } else { + log.error("An exception has occurred in Job '{}', But failed to send alert by Dingtalk because of: Unexpected response status: {}", jobName, status, cause); + } + } finally { + response.close(); + } Review comment: CloseableHttpResponse implement AutoCloseable. Replace finally with try-with-resources. ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/impl/DingtalkJobErrorHandler.java ########## @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.config.RequestConfig; +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.apache.shardingsphere.elasticjob.error.handler.JobErrorHandler; +import org.apache.shardingsphere.elasticjob.error.handler.config.DingtalkConfiguration; +import org.apache.shardingsphere.elasticjob.error.handler.env.DingtalkEnvironment; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Collections; + +/** + * Job error handler for dingtalk error message. + */ +@Slf4j +public final class DingtalkJobErrorHandler implements JobErrorHandler { + + @Setter + private DingtalkConfiguration dingtalkConfiguration; + + private CloseableHttpClient httpclient = HttpClients.createDefault(); + + public DingtalkJobErrorHandler() { + registerShutdownHook(); + } + + @SneakyThrows + @Override + public void handleException(final String jobName, final Throwable cause) { + if (null == dingtalkConfiguration) { + dingtalkConfiguration = DingtalkEnvironment.getInstance().getDingtalkConfiguration(); + } + HttpPost httpPost = new HttpPost(getUrl()); + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(dingtalkConfiguration.getConnectTimeout()) + .setSocketTimeout(dingtalkConfiguration.getReadTimeout()).build(); + httpPost.setConfig(requestConfig); + String paramJson = getParamJson(getMsg(jobName, cause)); + StringEntity entity = new StringEntity(paramJson, StandardCharsets.UTF_8.name()); Review comment: Just use "StandardCharsets.UTF_8". The "name()" is unnecessary. ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/impl/DingtalkJobErrorHandler.java ########## @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.config.RequestConfig; +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.apache.shardingsphere.elasticjob.error.handler.JobErrorHandler; +import org.apache.shardingsphere.elasticjob.error.handler.config.DingtalkConfiguration; +import org.apache.shardingsphere.elasticjob.error.handler.env.DingtalkEnvironment; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Collections; + +/** + * Job error handler for dingtalk error message. + */ +@Slf4j +public final class DingtalkJobErrorHandler implements JobErrorHandler { + + @Setter + private DingtalkConfiguration dingtalkConfiguration; + + private CloseableHttpClient httpclient = HttpClients.createDefault(); Review comment: This field may be "final". ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/impl/DingtalkJobErrorHandler.java ########## @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.config.RequestConfig; +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.apache.shardingsphere.elasticjob.error.handler.JobErrorHandler; +import org.apache.shardingsphere.elasticjob.error.handler.config.DingtalkConfiguration; +import org.apache.shardingsphere.elasticjob.error.handler.env.DingtalkEnvironment; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Collections; + +/** + * Job error handler for dingtalk error message. + */ +@Slf4j +public final class DingtalkJobErrorHandler implements JobErrorHandler { + + @Setter + private DingtalkConfiguration dingtalkConfiguration; + + private CloseableHttpClient httpclient = HttpClients.createDefault(); + + public DingtalkJobErrorHandler() { + registerShutdownHook(); + } + + @SneakyThrows + @Override + public void handleException(final String jobName, final Throwable cause) { + if (null == dingtalkConfiguration) { + dingtalkConfiguration = DingtalkEnvironment.getInstance().getDingtalkConfiguration(); + } + HttpPost httpPost = new HttpPost(getUrl()); + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(dingtalkConfiguration.getConnectTimeout()) + .setSocketTimeout(dingtalkConfiguration.getReadTimeout()).build(); + httpPost.setConfig(requestConfig); + String paramJson = getParamJson(getMsg(jobName, cause)); + StringEntity entity = new StringEntity(paramJson, StandardCharsets.UTF_8.name()); + entity.setContentEncoding(StandardCharsets.UTF_8.name()); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + CloseableHttpResponse response = httpclient.execute(httpPost); + try { + int status = response.getStatusLine().getStatusCode(); + if (HttpURLConnection.HTTP_OK == status) { + JsonObject resp = GsonFactory.getGson().fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class); + if (!"0".equals(resp.get("errcode").getAsString())) { + log.error("An exception has occurred in Job '{}', But failed to send alert by Dingtalk because of: {}", jobName, resp.get("errmsg").getAsString(), cause); + } else { + log.error("An exception has occurred in Job '{}', Notification to Dingtalk was successful.", jobName, cause); + } + } else { + log.error("An exception has occurred in Job '{}', But failed to send alert by Dingtalk because of: Unexpected response status: {}", jobName, status, cause); + } + } finally { + response.close(); + } + } + + private String getParamJson(final String msg) { + return GsonFactory.getGson().toJson(ImmutableMap.of("msgtype", "text", "text", Collections.singletonMap("content", msg))); + } + + private String getMsg(final String jobName, final Throwable cause) { + StringWriter sw = new StringWriter(); + cause.printStackTrace(new PrintWriter(sw, true)); + String msg = String.format("Job '%s' exception occur in job processing, caused by %s", jobName, sw.toString()); + if (!Strings.isNullOrEmpty(dingtalkConfiguration.getKeyword())) { + msg = dingtalkConfiguration.getKeyword().concat(msg); + } + return msg; + } + + private String getUrl() throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, MalformedURLException { + if (Strings.isNullOrEmpty(dingtalkConfiguration.getSecret())) { + return dingtalkConfiguration.getWebhook(); + } else { + return getSignUrl(); + } + } + + private String getSignUrl() throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException { + Long timestamp = System.currentTimeMillis(); + return String.format("%s×tamp=%s&sign=%s", dingtalkConfiguration.getWebhook(), timestamp, sign(timestamp)); + } + + private String sign(final Long timestamp) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException { + String stringToSign = timestamp + "\n" + dingtalkConfiguration.getSecret(); + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(dingtalkConfiguration.getSecret().getBytes(StandardCharsets.UTF_8.name()), "HmacSHA256")); + byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8.name())); Review comment: Just use "StandardCharsets.UTF_8". The "name()" is unnecessary for "getBytes". ########## File path: elasticjob-error-handler/elasticjob-error-handler-dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/impl/DingtalkJobErrorHandler.java ########## @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.elasticjob.error.handler.impl; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.config.RequestConfig; +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.apache.shardingsphere.elasticjob.error.handler.JobErrorHandler; +import org.apache.shardingsphere.elasticjob.error.handler.config.DingtalkConfiguration; +import org.apache.shardingsphere.elasticjob.error.handler.env.DingtalkEnvironment; +import org.apache.shardingsphere.elasticjob.infra.json.GsonFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Collections; + +/** + * Job error handler for dingtalk error message. + */ +@Slf4j +public final class DingtalkJobErrorHandler implements JobErrorHandler { + + @Setter + private DingtalkConfiguration dingtalkConfiguration; + + private CloseableHttpClient httpclient = HttpClients.createDefault(); + + public DingtalkJobErrorHandler() { + registerShutdownHook(); + } + + @SneakyThrows + @Override + public void handleException(final String jobName, final Throwable cause) { + if (null == dingtalkConfiguration) { + dingtalkConfiguration = DingtalkEnvironment.getInstance().getDingtalkConfiguration(); + } + HttpPost httpPost = new HttpPost(getUrl()); + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(dingtalkConfiguration.getConnectTimeout()) + .setSocketTimeout(dingtalkConfiguration.getReadTimeout()).build(); + httpPost.setConfig(requestConfig); + String paramJson = getParamJson(getMsg(jobName, cause)); + StringEntity entity = new StringEntity(paramJson, StandardCharsets.UTF_8.name()); + entity.setContentEncoding(StandardCharsets.UTF_8.name()); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + CloseableHttpResponse response = httpclient.execute(httpPost); + try { + int status = response.getStatusLine().getStatusCode(); + if (HttpURLConnection.HTTP_OK == status) { + JsonObject resp = GsonFactory.getGson().fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class); + if (!"0".equals(resp.get("errcode").getAsString())) { + log.error("An exception has occurred in Job '{}', But failed to send alert by Dingtalk because of: {}", jobName, resp.get("errmsg").getAsString(), cause); + } else { + log.error("An exception has occurred in Job '{}', Notification to Dingtalk was successful.", jobName, cause); + } + } else { + log.error("An exception has occurred in Job '{}', But failed to send alert by Dingtalk because of: Unexpected response status: {}", jobName, status, cause); + } + } finally { + response.close(); + } + } + + private String getParamJson(final String msg) { + return GsonFactory.getGson().toJson(ImmutableMap.of("msgtype", "text", "text", Collections.singletonMap("content", msg))); + } + + private String getMsg(final String jobName, final Throwable cause) { + StringWriter sw = new StringWriter(); + cause.printStackTrace(new PrintWriter(sw, true)); + String msg = String.format("Job '%s' exception occur in job processing, caused by %s", jobName, sw.toString()); + if (!Strings.isNullOrEmpty(dingtalkConfiguration.getKeyword())) { + msg = dingtalkConfiguration.getKeyword().concat(msg); + } + return msg; + } + + private String getUrl() throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, MalformedURLException { Review comment: MalformedURLException can be removed. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected]
