v3.2.0 Added inspection client and email service

prototype
Yan 7 months ago
parent be9d328eee
commit c0a0544923

1
.gitignore vendored

@ -5,3 +5,4 @@
/conf/
/conf2/
/bruno/
/backup/

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>camel-springboot-activemq6-example</artifactId>
<version>3.1.0</version>
<version>3.2.0</version>
<name>camel-springboot-activemq6-example</name>
<properties>
@ -19,6 +19,7 @@
<guava.version>33.1.0-jre</guava.version>
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
<jsoup.version>1.19.1</jsoup.version>
<java.mail.version>1.6.2</java.mail.version>
</properties>
<dependencyManagement>
@ -145,6 +146,20 @@
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>${java.mail.version}</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${java.mail.version}</version>
</dependency>
</dependencies>
<build>
<plugins>

@ -1,15 +1,52 @@
package com.example.sbcamel.init;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import com.example.sbcamel.processor.InspectionProcessor;
import com.example.sbcamel.processor.TestProcessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
@Configuration
@ImportResource("classpath:schedule.xml")
public class AppConfig {
@Value("${app.inspection-client.javamail-config}")
private String javamailCfg;
@Bean
public Properties javaMailProperties() throws IOException {
Properties javaMailProperties = new Properties();
FileInputStream fis = new FileInputStream(javamailCfg);
javaMailProperties.load(fis);
fis.close();
return javaMailProperties;
}
@Bean
public CloseableHttpClient httpClient() {
return HttpClients.createDefault();
}
@Bean("objectMapper")
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.registerModule(new Jdk8Module());
return mapper;
}
@Bean
public JacksonJsonProvider jaxrsProvider() {
return new JacksonJsonProvider();

@ -70,20 +70,18 @@ public class CamelRouter extends RouteBuilder {
exchange.getIn().getHeader(CxfConstants.OPERATION_NAME.toLowerCase())))
.to("log:activemq?showAll=true").transacted("propagationRequired").choice()
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("updateSession"))
.to("mybatis:" + SessionMapper.class.getName() + ".updateSession?statementType=Update&outputHeader=X-UpdateResult")
.to("mybatis:" + SessionMapper.class.getName()
+ ".updateSession?statementType=Update&outputHeader=X-UpdateResult")
.process(exchange -> {
exchange.getMessage().setBody(exchange.getIn().getBody());
})
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findSessions"))
}).when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findSessions"))
.to("mybatis:" + SessionMapper.class.getName() + ".findSessions?statementType=SelectList")
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findSession"))
.to("mybatis:" + SessionMapper.class.getName() + ".findSession?statementType=SelectOne")
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("inspect"))
.to("mybatis:" + SessionMapper.class.getName() + ".findSession?statementType=SelectOne")
.process(inspectionProcessor)
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("test"))
.process(testProcessor)
.end().marshal().json(JsonLibrary.Jackson);
.process(inspectionProcessor).when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("test"))
.process(testProcessor).end().marshal().json(JsonLibrary.Jackson);
}
}

@ -35,8 +35,8 @@ public class SecurityConfig {
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorize) -> authorize.requestMatchers(HttpMethod.GET, "/**")
.hasAuthority(ROLE_BACKEND).requestMatchers(HttpMethod.POST, "/**").hasAuthority(ROLE_SERVER)
.requestMatchers(HttpMethod.PUT, "/**").permitAll())
.httpBasic(Customizer.withDefaults()).csrf(csrf -> csrf.disable());
.requestMatchers(HttpMethod.PUT, "/**").permitAll()).httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable());
return http.build();
}

@ -1,5 +1,7 @@
package com.example.sbcamel.processor;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -7,6 +9,7 @@ import java.util.Map;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.WebClient;
import org.htmlunit.html.HtmlButton;
import org.htmlunit.html.HtmlForm;
@ -54,76 +57,58 @@ public class InspectionProcessor implements Processor {
@Override
public void process(Exchange exchange) throws Exception {
Session session = (Session) exchange.getMessage().getBody();
logger.info("session: {}", session);
logger.debug("session: {}", session);
try (final WebClient webClient = new WebClient()) {
final HtmlPage loginPage = webClient.getPage(loginUrl);
logger.info("loginPage: {}", loginPage.asXml());
logger.debug("loginPage: {}", loginPage.asXml());
final HtmlForm form = loginPage.getForms().get(0);
final HtmlTextInput usernameField = form.getInputByName("username");
usernameField.type(session.getUsername());
logger.info("entered username: {}", session.getUsername());
logger.debug("entered username: {}", session.getUsername());
final HtmlPasswordInput passwordField = form.getInputByName("password");
passwordField.type(session.getPassword());
logger.info("entered password: {}", session.getPassword());
logger.debug("entered password: {}", session.getPassword());
HtmlButton loginBtn = loginPage.querySelector(loginBtnSelector);
logger.info("loginBtn type: {}", loginBtn.getType());
logger.debug("loginBtn type: {}", loginBtn.getType());
loginBtn.click();
Thread.sleep(loginWaitMillis);
HtmlPage userPage = webClient.getPage(userPageUrl);
logger.info("userPage hashcode: {}", userPage.hashCode());
logger.debug("userPage hashcode: {}", userPage.hashCode());
Map<String, List<String>> reply1 = new HashMap<>();
HtmlPage vip1Page = webClient.getPage(vip1PageUrl);
Document doc = Jsoup.parse(vip1Page.asXml());
for (String selector : List.of(session.getSelector1(), session.getSelector2(), session.getSelector3())) {
Elements elements = doc.select(selector);
List<String> selectedList = new ArrayList<>();
for (Element element : elements) {
logger.info("[vip1Page] {} -> {}", selector, element.html());
selectedList.add(element.html());
}
reply1.put(selector, selectedList);
}
Map<String, List<String>> reply1 = fillResponseMap(webClient, session, vip1PageUrl);
Map<String, List<String>> reply2 = fillResponseMap(webClient, session, vip2PageUrl);
Map<String, List<String>> reply3 = fillResponseMap(webClient, session, vip3PageUrl);
Map<String, List<String>> reply2 = new HashMap<>();
HtmlPage vip2Page = webClient.getPage(vip2PageUrl);
doc = Jsoup.parse(vip2Page.asXml());
for (String selector : List.of(session.getSelector1(), session.getSelector2(), session.getSelector3())) {
Elements elements = doc.select(selector);
List<String> selectedList = new ArrayList<>();
for (Element element : elements) {
logger.info("[vip2Page] {} -> {}", selector, element.html());
selectedList.add(element.html());
webClient.getPage(logoutUrl);
exchange.getMessage().setBody(Map.of("vip1Page", reply1, "vip2Page", reply2, "vip3Page", reply3));
} catch (Exception e) {
logger.error("LoginProcessor process error!", e);
}
reply2.put(selector, selectedList);
}
Map<String, List<String>> reply3 = new HashMap<>();
HtmlPage vip3Page = webClient.getPage(vip3PageUrl);
doc = Jsoup.parse(vip3Page.asXml());
private Map<String, List<String>> fillResponseMap(WebClient webClient, Session session, String url)
throws FailingHttpStatusCodeException, MalformedURLException, IOException {
Map<String, List<String>> reply = new HashMap<>();
HtmlPage vipPage = webClient.getPage(url);
Document doc = Jsoup.parse(vipPage.asXml());
for (String selector : List.of(session.getSelector1(), session.getSelector2(), session.getSelector3())) {
Elements elements = doc.select(selector);
List<String> selectedList = new ArrayList<>();
for (Element element : elements) {
logger.info("[vip3Page] {} -> {}", selector, element.html());
logger.debug("[fillResponseMap] {} -> {}", selector, element.html());
selectedList.add(element.html());
}
reply3.put(selector, selectedList);
}
webClient.getPage(logoutUrl);
exchange.getMessage().setBody(Map.of("vip1Page", reply1, "vip2Page", reply2, "vip3Page", reply3));
} catch (Exception e) {
logger.error("LoginProcessor process error!", e);
reply.put(selector, selectedList);
}
return reply;
}
}

@ -0,0 +1,70 @@
package com.example.sbcamel.service;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EmailService {
private static final Logger logger = LoggerFactory.getLogger(EmailService.class);
@Autowired
private Properties javaMailProperties;
public boolean sendEmail(String fromAddress, String smtpPassword, String[] toAddresses, String subject,
String content) {
try {
logger.debug("[sendEmail] fromAddress: {}, toAddresses: {}", fromAddress, toAddresses);
if (StringUtils.isEmpty(subject) || StringUtils.isEmpty(smtpPassword) || StringUtils.isEmpty(fromAddress)
|| toAddresses.length == 0) {
logger.warn("[sendEmail] subject, smtp-password, source-address or target-address is not set");
return false;
}
String emailHost = javaMailProperties.getProperty("mail.smtp.host");
logger.debug("[sendEmail] {} -> {}, mail.smtp.host: {}", fromAddress, List.of(toAddresses), emailHost);
if (StringUtils.isNotBlank(emailHost) && StringUtils.isNotBlank(fromAddress) && toAddresses.length > 0) {
logger.debug("[sendEmail] starting to send message from: {}", fromAddress);
Session session = Session.getInstance(javaMailProperties);
MimeMessage message = new MimeMessage(session);
message.setContent(content, "text/html; charset=utf-8");
message.setFrom(new InternetAddress(fromAddress));
Arrays.asList(toAddresses).forEach(toAddress -> {
try {
message.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
} catch (Exception e) {
logger.error("sendEmail error!", e);
}
});
message.setSubject(subject);
Transport transport = session.getTransport("smtp");
transport.connect(emailHost, fromAddress, smtpPassword);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
logger.debug("sendEmail to: {}", Arrays.asList(toAddresses));
return true;
} else {
logger.warn("[sendEmail] missing either from-field, to-field or host address!");
}
} catch (Exception e) {
logger.error("sendEmail error!", e);
}
return false;
}
}

@ -0,0 +1,161 @@
package com.example.sbcamel.service;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.MapDifference;
import com.google.common.collect.MapDifference.ValueDifference;
import com.google.common.collect.Maps;
public class InspectionClient {
private static final Logger logger = LoggerFactory.getLogger(InspectionClient.class);
@Autowired
private CloseableHttpClient httpClient;
@Autowired
private EmailService emailService;
@Autowired
private ObjectMapper objectMapper;
@Value("${app.inspection-client.email-password:}")
private String smtpPassword;
@Value("${app.inspection-client.email-sender:}")
private String fromAddress;
@Value("${app.inspection-client.email-recipient:}")
private String[] toAddresses;
@Value("${app.inspection-client.http-url}")
private String url;
@Value("${app.inspection-client.http-method}")
private String httpMethod;
@Value("${app.inspection-client.expected-result-file-path}")
private String expectedResultFilePath;
@Value("${app.inspection-client.alert-subject}")
private String alertSubject;
@Value("${app.inspection-client.http-username}")
private String username;
@Value("${app.inspection-client.http-password}")
private String password;
private static final String getBasicAuthenticationHeader(String username, String password) {
String valueToEncode = username + ":" + password;
return "Basic " + Base64.getEncoder().encodeToString(valueToEncode.getBytes());
}
public void sendMessage() {
try {
File jsonFile = new File(expectedResultFilePath);
if (!jsonFile.exists()) {
logger.info("file does not exist: {}", expectedResultFilePath);
return;
}
String jsonString = FileUtils.readFileToString(jsonFile, StandardCharsets.UTF_8);
logger.info("expected result: {}", jsonString);
HashMap<String, Object> expectedMap = convertStringToMap(jsonString);
logger.info("calling {} {}", httpMethod, url);
HttpUriRequestBase req = new HttpUriRequestBase(httpMethod, URI.create(url));
req.addHeader("Authorization", getBasicAuthenticationHeader(username, password));
Pair<Boolean, Boolean> sendEmailResult = httpClient.execute(req,
new HttpClientResponseHandler<Pair<Boolean, Boolean>>() {
@Override
public Pair<Boolean, Boolean> handleResponse(ClassicHttpResponse result)
throws HttpException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
result.getEntity().writeTo(baos);
String responseText = new String(baos.toByteArray(), StandardCharsets.UTF_8);
logger.info("actual result: {}", responseText);
if (StringUtils.isEmpty(responseText)) {
logger.error("actual result is empty!");
return Pair.of(Boolean.FALSE, Boolean.FALSE);
}
baos.close();
try {
HashMap<String, Object> resultMap = convertStringToMap(responseText);
MapDifference<String, Object> diff = Maps.difference(expectedMap, resultMap);
logger.info("diff.areEqual: {}", diff.areEqual());
StringBuilder contentBuilder = new StringBuilder();
if (!diff.areEqual()) {
Map<String, ValueDifference<Object>> entriesDiffering = diff.entriesDiffering();
entriesDiffering.entrySet().stream().forEach(entry -> {
logger.info("entriesDiffering key: {}", entry.getKey());
logger.info("entriesDiffering expected: {}", entry.getValue().leftValue());
logger.info("entriesDiffering actual: {}", entry.getValue().rightValue());
contentBuilder.append(entry.getKey() + "\n");
contentBuilder.append("EXPECTED: " + entry.getValue().leftValue() + "\n");
contentBuilder.append("ACTUAL: " + entry.getValue().rightValue() + "\n");
contentBuilder.append("\n");
});
return Pair.of(Boolean.TRUE, emailService.sendEmail(fromAddress, smtpPassword,
toAddresses, alertSubject, contentBuilder.toString()));
}
} catch (IOException e) {
logger.error("Error occurred while parsing message", e);
}
return Pair.of(Boolean.FALSE, Boolean.FALSE);
}
});
logger.info("send email result: {}", sendEmailResult);
} catch (Exception e) {
logger.error("Error occurred while preparing to send message", e);
}
}
public HashMap<String, Object> convertStringToMap(String jsonString) throws IOException {
TypeReference<java.util.HashMap<String, Object>> ref = new TypeReference<>() {
};
return new HashMap<>(objectMapper.readValue(jsonString, ref));
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getHttpMethod() {
return httpMethod;
}
public void setHttpMethod(String httpMethod) {
this.httpMethod = httpMethod;
}
}

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task https://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<task:scheduler id="inspectionScheduler" pool-size="2" />
<bean id="inspectionClient"
class="com.example.sbcamel.service.InspectionClient">
</bean>
<task:scheduled-tasks scheduler="inspectionScheduler">
<task:scheduled ref="inspectionClient"
method="sendMessage" cron="0 * * * * ?" />
</task:scheduled-tasks>
</beans>
Loading…
Cancel
Save