diff --git a/.gitignore b/.gitignore
index 789da79..185ccfb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
/conf/
/conf2/
/bruno/
+/backup/
diff --git a/pom.xml b/pom.xml
index 9253941..8161b0e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.example
camel-springboot-activemq6-example
- 3.1.0
+ 3.2.0
camel-springboot-activemq6-example
@@ -19,6 +19,7 @@
33.1.0-jre
3.14.0
1.19.1
+ 1.6.2
@@ -145,6 +146,20 @@
jsoup
${jsoup.version}
+
+ org.apache.httpcomponents.client5
+ httpclient5
+
+
+ javax.mail
+ javax.mail-api
+ ${java.mail.version}
+
+
+ com.sun.mail
+ javax.mail
+ ${java.mail.version}
+
diff --git a/src/main/java/com/example/sbcamel/init/AppConfig.java b/src/main/java/com/example/sbcamel/init/AppConfig.java
index 92fb308..47b5150 100644
--- a/src/main/java/com/example/sbcamel/init/AppConfig.java
+++ b/src/main/java/com/example/sbcamel/init/AppConfig.java
@@ -1,25 +1,62 @@
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();
}
-
+
@Bean
public InspectionProcessor inspectionProcessor() {
return new InspectionProcessor();
}
-
+
@Bean
public TestProcessor testProcessor() {
return new TestProcessor();
diff --git a/src/main/java/com/example/sbcamel/init/CamelRouter.java b/src/main/java/com/example/sbcamel/init/CamelRouter.java
index d0f72ff..9475d50 100644
--- a/src/main/java/com/example/sbcamel/init/CamelRouter.java
+++ b/src/main/java/com/example/sbcamel/init/CamelRouter.java
@@ -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);
}
}
\ No newline at end of file
diff --git a/src/main/java/com/example/sbcamel/init/SecurityConfig.java b/src/main/java/com/example/sbcamel/init/SecurityConfig.java
index 94bc962..5e58fa3 100644
--- a/src/main/java/com/example/sbcamel/init/SecurityConfig.java
+++ b/src/main/java/com/example/sbcamel/init/SecurityConfig.java
@@ -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();
}
@@ -56,5 +56,5 @@ public class SecurityConfig {
factory.setUserSearchFilter(userSearchFilter);
factory.setLdapAuthoritiesPopulator(authorities);
return factory.createAuthenticationManager();
- }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/example/sbcamel/processor/InspectionProcessor.java b/src/main/java/com/example/sbcamel/processor/InspectionProcessor.java
index aee970a..42be66e 100644
--- a/src/main/java/com/example/sbcamel/processor/InspectionProcessor.java
+++ b/src/main/java/com/example/sbcamel/processor/InspectionProcessor.java
@@ -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,69 +57,34 @@ 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());
-
- Map> 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 selectedList = new ArrayList<>();
- for (Element element : elements) {
- logger.info("[vip1Page] {} -> {}", selector, element.html());
- selectedList.add(element.html());
- }
- reply1.put(selector, selectedList);
- }
- Map> 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 selectedList = new ArrayList<>();
- for (Element element : elements) {
- logger.info("[vip2Page] {} -> {}", selector, element.html());
- selectedList.add(element.html());
- }
- reply2.put(selector, selectedList);
- }
+ HtmlPage userPage = webClient.getPage(userPageUrl);
+ logger.debug("userPage hashcode: {}", userPage.hashCode());
- Map> reply3 = new HashMap<>();
- HtmlPage vip3Page = webClient.getPage(vip3PageUrl);
- doc = Jsoup.parse(vip3Page.asXml());
- for (String selector : List.of(session.getSelector1(), session.getSelector2(), session.getSelector3())) {
- Elements elements = doc.select(selector);
- List selectedList = new ArrayList<>();
- for (Element element : elements) {
- logger.info("[vip3Page] {} -> {}", selector, element.html());
- selectedList.add(element.html());
- }
- reply3.put(selector, selectedList);
- }
+ Map> reply1 = fillResponseMap(webClient, session, vip1PageUrl);
+ Map> reply2 = fillResponseMap(webClient, session, vip2PageUrl);
+ Map> reply3 = fillResponseMap(webClient, session, vip3PageUrl);
webClient.getPage(logoutUrl);
exchange.getMessage().setBody(Map.of("vip1Page", reply1, "vip2Page", reply2, "vip3Page", reply3));
@@ -126,4 +94,21 @@ public class InspectionProcessor implements Processor {
}
}
+ private Map> fillResponseMap(WebClient webClient, Session session, String url)
+ throws FailingHttpStatusCodeException, MalformedURLException, IOException {
+ Map> 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 selectedList = new ArrayList<>();
+ for (Element element : elements) {
+ logger.debug("[fillResponseMap] {} -> {}", selector, element.html());
+ selectedList.add(element.html());
+ }
+ reply.put(selector, selectedList);
+ }
+ return reply;
+ }
+
}
diff --git a/src/main/java/com/example/sbcamel/processor/TestProcessor.java b/src/main/java/com/example/sbcamel/processor/TestProcessor.java
index 4a32876..1e1affa 100644
--- a/src/main/java/com/example/sbcamel/processor/TestProcessor.java
+++ b/src/main/java/com/example/sbcamel/processor/TestProcessor.java
@@ -17,28 +17,28 @@ import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.annotation.Value;
public class TestProcessor implements Processor {
-
+
private static final Logger logger = LoggerFactory.getLogger(TestProcessor.class);
@Value("${app.jsoup.html-file}")
private String htmlFilePath;
-
+
@SuppressWarnings("unchecked")
@Override
- public void process(Exchange exchange) throws Exception {
+ public void process(Exchange exchange) throws Exception {
logger.info("in class: {}", exchange.getIn().getBody().getClass().getName());
MessageContentsList mcl = (MessageContentsList) exchange.getIn().getBody();
List selectors = (List) mcl.get(0);
logger.info("selectors: {}", selectors);
-
+
File htmlFile = new File(htmlFilePath);
String html = FileUtils.readFileToString(htmlFile, StandardCharsets.UTF_8);
Document doc = Jsoup.parse(html);
Map> reply = new HashMap<>();
-
+
for (String selector : selectors) {
Elements elements = doc.select(selector);
List selectedList = new ArrayList<>();
diff --git a/src/main/java/com/example/sbcamel/service/EmailService.java b/src/main/java/com/example/sbcamel/service/EmailService.java
new file mode 100644
index 0000000..66048dd
--- /dev/null
+++ b/src/main/java/com/example/sbcamel/service/EmailService.java
@@ -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;
+ }
+}
diff --git a/src/main/java/com/example/sbcamel/service/InspectionClient.java b/src/main/java/com/example/sbcamel/service/InspectionClient.java
new file mode 100644
index 0000000..4d78a2b
--- /dev/null
+++ b/src/main/java/com/example/sbcamel/service/InspectionClient.java
@@ -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 expectedMap = convertStringToMap(jsonString);
+ logger.info("calling {} {}", httpMethod, url);
+
+ HttpUriRequestBase req = new HttpUriRequestBase(httpMethod, URI.create(url));
+ req.addHeader("Authorization", getBasicAuthenticationHeader(username, password));
+ Pair sendEmailResult = httpClient.execute(req,
+ new HttpClientResponseHandler>() {
+
+ @Override
+ public Pair 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 resultMap = convertStringToMap(responseText);
+ MapDifference diff = Maps.difference(expectedMap, resultMap);
+ logger.info("diff.areEqual: {}", diff.areEqual());
+ StringBuilder contentBuilder = new StringBuilder();
+ if (!diff.areEqual()) {
+ Map> 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 convertStringToMap(String jsonString) throws IOException {
+ TypeReference> 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;
+ }
+}
diff --git a/src/main/java/com/example/sbcamel/service/Session.java b/src/main/java/com/example/sbcamel/service/Session.java
index 0e431f0..878262b 100644
--- a/src/main/java/com/example/sbcamel/service/Session.java
+++ b/src/main/java/com/example/sbcamel/service/Session.java
@@ -24,13 +24,13 @@ public class Session implements Serializable {
@NotNull
@Size(min = 3, max = 40)
private String password;
-
+
@NotNull
private String selector1;
-
+
@NotNull
private String selector2;
-
+
@NotNull
private String selector3;
diff --git a/src/main/java/com/example/sbcamel/service/SessionService.java b/src/main/java/com/example/sbcamel/service/SessionService.java
index a8e5f3f..f0da502 100644
--- a/src/main/java/com/example/sbcamel/service/SessionService.java
+++ b/src/main/java/com/example/sbcamel/service/SessionService.java
@@ -33,12 +33,12 @@ public interface SessionService {
@Path("/session")
@Produces(MediaType.APPLICATION_JSON)
Collection findSessions();
-
+
@POST
@Path("/inspect/{sessionId}")
@Produces(MediaType.APPLICATION_JSON)
Map> inspect(@PathParam("sessionId") UUID sessionId);
-
+
@POST
@Path("/test")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/src/main/resources/schedule.xml b/src/main/resources/schedule.xml
new file mode 100644
index 0000000..1f11a2f
--- /dev/null
+++ b/src/main/resources/schedule.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file