Commit 27836524 authored by Aaron Gutierrez's avatar Aaron Gutierrez

Cambios para dashboard hdi

parent fc4d0496
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<groupId>com.bytesw.bytebot</groupId> <groupId>com.bytesw.bytebot</groupId>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>bytebot-service</artifactId> <artifactId>bytebot-service</artifactId>
<version>1.0.0</version> <version>1.0.1</version>
<packaging>jar</packaging> <packaging>jar</packaging>
...@@ -70,6 +70,23 @@ ...@@ -70,6 +70,23 @@
<version>${json-path.version}</version> <version>${json-path.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency> <dependency>
<groupId>org.everit.json</groupId> <groupId>org.everit.json</groupId>
<artifactId>org.everit.json.schema</artifactId> <artifactId>org.everit.json.schema</artifactId>
...@@ -179,6 +196,17 @@ ...@@ -179,6 +196,17 @@
<version>4.1.2</version> <version>4.1.2</version>
</dependency> </dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.18</version>
</dependency>
<dependency>
<groupId>org.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>1.3.3</version>
</dependency>
<!-- websocket--> <!-- websocket-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
......
package com.bytesw.bytebot; package com.bytesw.bytebot;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
...@@ -12,6 +13,7 @@ import org.springframework.context.annotation.ImportResource; ...@@ -12,6 +13,7 @@ import org.springframework.context.annotation.ImportResource;
@EnableCaching @EnableCaching
@EnableAspectJAutoProxy @EnableAspectJAutoProxy
@EnableFeignClients(basePackages = "com.bytesw") @EnableFeignClients(basePackages = "com.bytesw")
@EnableBatchProcessing
public class BytebotApplication { public class BytebotApplication {
public static void main(String[] args) { public static void main(String[] args) {
......
package com.bytesw.bytebot.bean;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigInteger;
@Getter @Setter
public class ActionSummaryByGoalBean implements Serializable {
@Expose
private String goal;
@Expose
private BigInteger count;
}
package com.bytesw.bytebot.bean;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigDecimal;
@Getter @Setter
public class AverageBean implements Serializable {
@Expose
private BigDecimal firstResponseAverage;
@Expose
private BigDecimal sessionAverage;
}
package com.bytesw.bytebot.bean;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigInteger;
@Getter @Setter
public class MessageByIntentBean implements Serializable {
@Expose
private String identifier;
@Expose
private BigInteger count;
}
package com.bytesw.bytebot.bean;
import lombok.Getter;
import lombok.Setter;
import java.time.OffsetDateTime;
@Getter @Setter
public class RangeBean {
private OffsetDateTime startDate;
private OffsetDateTime endDate;
}
package com.bytesw.bytebot.bean;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
@Getter @Setter
public class SummaryBean implements Serializable {
@Expose
private BigInteger value;
@Expose
private List<BigInteger> history;
@Expose
private BigDecimal percent;
@Expose
private boolean up = false;
@Expose
private boolean down = false;
}
package com.bytesw.bytebot.bean;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigInteger;
@Getter @Setter
public class SummaryMessageByIntentBean implements Serializable {
@Expose
private Long id;
@Expose
private String identifier;
@Expose
private BigInteger count;
}
package com.bytesw.bytebot.bean;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigInteger;
@Getter @Setter
public class SummaryMessageBySentenceBean implements Serializable {
@Expose
private Long id;
@Expose
private String identifier;
@Expose
private String sentence;
@Expose
private BigInteger count;
@Expose
private BigInteger customerCount;
}
package com.bytesw.bytebot.controller;
import com.google.gson.GsonBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@RestController
public class AppSettingsController {
@Value("${application.logo.type:png}")
private String type;
@Value("classpath:logo.txt")
Resource resourceFile;
@Value("${application.show-side-bar:true}")
private boolean showSideBar;
@Autowired
private GsonBuilder gsonBuilder;
@GetMapping("/settings/information")
public ResponseEntity<String> getAppSettings() {
HttpStatus hs = HttpStatus.OK;
Map<String, Object> appSettings = new HashMap<>();
appSettings.put("tipo", type);
appSettings.put("logoBase64", getDefaultLogo());
//you
// appSettings.put("showSideBar", true);
return new ResponseEntity<>(gsonBuilder.disableHtmlEscaping().create().toJson(appSettings), hs);
}
public String getDefaultLogo() {
String str = "";
StringBuffer buf = new StringBuffer();
InputStream is = null;
try {
is = resourceFile.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
if (is != null) {
while ((str = reader.readLine()) != null) {
buf.append(str + "" );
}
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try { is.close(); } catch (Throwable ignore) {}
}
return buf.toString();
}
}
package com.bytesw.bytebot.controller;
import com.bytesw.bytebot.bean.AgentBean;
import com.bytesw.bytebot.bean.SummaryMessageBySentenceBean;
import com.bytesw.bytebot.service.dashboard.CustomerInteractionDashboardService;
import com.bytesw.bytebot.service.dashboard.OperativeDashboardService;
import com.bytesw.xdf.sql.beans.Pagination;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/dashboard")
public class DashboardController {
@Autowired
private OperativeDashboardService operativeDashboardService;
@Autowired
private CustomerInteractionDashboardService customerInteractionDashboardService;
@Autowired
private Gson gson;
@PostMapping("/operative")
public ResponseEntity<String> getOperativeInfo(@RequestBody Map<String, Object> body) {
Map<String, Object> info = operativeDashboardService.generateInfo(body);
return new ResponseEntity<>(gson.toJson(info), HttpStatus.OK);
}
@PostMapping("/operative/sentence-by-intent/page")
public ResponseEntity<String> getSentenceByIntentPage(@RequestBody Pagination<SummaryMessageBySentenceBean> pagination) {
customerInteractionDashboardService.getSummaryBySentencePagination(pagination);
return new ResponseEntity<>(gson.toJson(pagination), HttpStatus.OK);
}
@PostMapping("/customer-interaction")
public ResponseEntity<String> getCustomerInteractionInfo(@RequestBody Map<String, Object> body) {
Map<String, Object> info = customerInteractionDashboardService.generateInfo(body);
return new ResponseEntity<>(gson.toJson(info), HttpStatus.OK);
}
@PostMapping("/customer-interaction/message-by-intent/page")
public ResponseEntity<String> getMessageByIntentPage(@RequestBody Pagination<SummaryMessageBySentenceBean> pagination) {
customerInteractionDashboardService.getSummaryByIntentAndSentencePagination(pagination);
return new ResponseEntity<>(gson.toJson(pagination), HttpStatus.OK);
}
@GetMapping("/test")
public ResponseEntity<String> getTest() {
Map<String, Object> data = customerInteractionDashboardService.generateInfo(new HashMap<>());
return new ResponseEntity<>(gson.toJson(data), HttpStatus.OK);
}
}
package com.bytesw.bytebot.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthController {
@GetMapping("/health")
public ResponseEntity<Void> health() {
return new ResponseEntity<>(HttpStatus.OK);
}
}
package com.bytesw.bytebot.etl.batch.beans;
import lombok.*;
import java.io.Serializable;
@Getter @Setter
@EqualsAndHashCode
@AllArgsConstructor
@ToString
public class AttributeValueBean implements Serializable {
private final String identifier;
private String value;
private final Long dataTypeId;
}
package com.bytesw.bytebot.etl.batch.beans;
import java.util.HashMap;
public class DynaBean extends HashMap<String, Object> {
}
package com.bytesw.bytebot.etl.batch.beans;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Getter @Setter
public class TenantBatchBean {
private String id;
private Map<String, String> datasource;
}
package com.bytesw.bytebot.etl.batch.factory.mapper;
import java.util.Map;
public interface MapperFactory<T> {
T createMapper(Map<String, Object> params);
}
package com.bytesw.bytebot.etl.batch.factory.mapper;
import com.bytesw.bytebot.etl.batch.beans.DynaBean;
import com.bytesw.bytebot.etl.batch.mapper.DynaBeanRowMapper;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class RowMapperFactory implements MapperFactory<DynaBeanRowMapper<DynaBean>>{
@Override
public DynaBeanRowMapper<DynaBean> createMapper(Map<String, Object> params) {
DynaBeanRowMapper<DynaBean> rowMapper = new DynaBeanRowMapper<>();
return rowMapper;
}
}
package com.bytesw.bytebot.etl.batch.factory.reader;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.item.database.JdbcCursorItemReader;
@Log4j2
public class ByteDataBaseItemReaderFactory<T> extends JdbcCursorItemReader<T> implements StepExecutionListener {
@Override
public void beforeStep(StepExecution stepExecution) {
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
closeDatabase();
return stepExecution.getExitStatus();
}
private void closeDatabase() {
if (this.getDataSource() instanceof BasicDataSource) {
BasicDataSource dataSource = (BasicDataSource) this.getDataSource();
if (!dataSource.isClosed()) {
try {
dataSource.close();
} catch (Exception e) {
log.debug(e.getMessage());
}
}
}
}
}
package com.bytesw.bytebot.etl.batch.factory.reader;
import com.bytesw.bytebot.etl.batch.beans.DynaBean;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import javax.sql.DataSource;
import java.util.Map;
/**
* Params:
* -jdbc-driver
* -username
* -password
* -jdbc-url
* -query
*/
@Component
public class DataBaseItemReaderFactory implements ItemReaderFactory<DynaBean, RowMapper<DynaBean>> {
@Override
public ItemReader<DynaBean> createReader(RowMapper<DynaBean> mapper, Map<String, Object> params) {
JdbcCursorItemReader<DynaBean> databaseReader;
databaseReader = new ByteDataBaseItemReaderFactory<>();
String jdbcDriver = params.containsKey("jdbc-driver") ? String.valueOf(params.get("jdbc-driver")): null;;
Assert.isTrue(jdbcDriver != null, "jdbc-driver is required!");
String username = params.containsKey("username") ? String.valueOf(params.get("username")): null;;
Assert.isTrue(username != null, "username is required!");
String password = params.containsKey("password") ? String.valueOf(params.get("password")): null;;
Assert.isTrue(password != null, "password is required!");
String jdbcURL = params.containsKey("jdbc-url") ? String.valueOf(params.get("jdbc-url")): null;;
Assert.isTrue(jdbcURL != null, "jdbc-url is required!");
String query = params.containsKey("query") ? String.valueOf(params.get("query")): null;;
Assert.isTrue(query != null, "query is required!");
DataSource dataSource = getBasicDataSource(jdbcDriver, username, password, jdbcURL);
databaseReader.setDataSource(dataSource);
databaseReader.setRowMapper(mapper);
databaseReader.setSql(query);
return databaseReader;
}
protected DataSource getBasicDataSource(String jdbcDriver, String username, String password, String jdbcURL) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(jdbcDriver);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setUrl(jdbcURL);
return dataSource;
}
}
package com.bytesw.bytebot.etl.batch.factory.reader;
import org.springframework.batch.item.ItemReader;
import java.util.Map;
public interface ItemReaderFactory<T, E> {
ItemReader<T> createReader(E mapper, Map<String, Object> params);
}
package com.bytesw.bytebot.etl.batch.listener;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
public class JobCompletionListener extends JobExecutionListenerSupport {
@Override
public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
System.out.println("BATCH JOB COMPLETED SUCCESSFULLY");
}
}
}
\ No newline at end of file
package com.bytesw.bytebot.etl.batch.mapper;
import com.bytesw.bytebot.etl.batch.beans.DynaBean;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
public class DynaBeanRowMapper<T> implements RowMapper<T> {
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
DynaBean bean = new DynaBean();
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String column = JdbcUtils.lookupColumnName(rsmd, i);
bean.putIfAbsent(column, JdbcUtils.getResultSetValue(rs, i));
}
return (T) bean;
}
}
package com.bytesw.bytebot.etl.batch.processor;
import com.bytesw.bytebot.etl.batch.beans.DynaBean;
import com.bytesw.bytebot.etl.beans.EventBean;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.batch.item.ItemProcessor;
@Log4j2
public class ConvertToBeanProcessor implements ItemProcessor<DynaBean, DynaBean> {
private ObjectMapper mapper = new ObjectMapper();
@Override
public DynaBean process(DynaBean dynaBean) throws Exception {
Long id = new Long(String.valueOf(dynaBean.get("id")));
String data = (String) dynaBean.get("data");
String senderId = (String) dynaBean.get("sender_id");
EventBean eventBean = new EventBean();
eventBean.setId(id);
eventBean.setData(data);
eventBean.setSenderId(senderId);
dynaBean.put("bean", eventBean);
return dynaBean;
}
}
package com.bytesw.bytebot.etl.batch.service;
import com.bytesw.bytebot.etl.batch.beans.DynaBean;
import com.bytesw.bytebot.etl.batch.beans.TenantBatchBean;
import com.bytesw.bytebot.etl.batch.factory.mapper.RowMapperFactory;
import com.bytesw.bytebot.etl.batch.factory.reader.DataBaseItemReaderFactory;
import com.bytesw.bytebot.etl.batch.processor.ConvertToBeanProcessor;
import com.bytesw.bytebot.etl.batch.writer.ByteBotJPAWriter;
import com.bytesw.bytebot.etl.config.BatchProperties;
import com.bytesw.bytebot.etl.dao.EventHistoryRepository;
import com.bytesw.bytebot.etl.services.ProcessMessageService;
import com.bytesw.xdf.multitenant.core.ThreadLocalStorage;
import com.google.gson.Gson;
import lombok.extern.log4j.Log4j2;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
@Service
@Log4j2
public class ScheduleService implements SchedulingConfigurer {
ScheduledTaskRegistrar scheduledTaskRegistrar;
Map<String, ScheduledFuture> futureMap = new HashMap<>();
@Autowired
@Qualifier("schedulerLockTaskScheduler")
TaskScheduler poolScheduler;
@Value("${application.byte-bot.batch.cron: 0 0/1 * * * * }")
private String cronExpression;
@Value("${application.byte-bot.batch.chunk:500}")
private int chunk;
@Autowired
private JobExplorer jobExplorer;
@Autowired
@Qualifier("asyncJobLauncher")
JobLauncher asyncJobLauncher;
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Autowired
private DataBaseItemReaderFactory dataBaseItemReaderFactory;
@Autowired
private RowMapperFactory rowMapperFactory;
@Autowired
private JobExecutionListener listener;
@Autowired
private ProcessMessageService service;
@Autowired
private Gson gson;
@Autowired
private BatchProperties properties;
@Autowired
private EventHistoryRepository eventHistoryRepository;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
if (scheduledTaskRegistrar == null) {
scheduledTaskRegistrar = taskRegistrar;
}
if (taskRegistrar.getScheduler() == null) {
taskRegistrar.setScheduler(poolScheduler);
}
if (properties == null) {
throw new RuntimeException("batch properties not found");
}
if (properties.getTenants() == null) {
throw new RuntimeException("batch properties not found");
}
properties.getTenants().stream().forEach(tenant -> {
ThreadLocalStorage.setTenantName(tenant.getId());
configureTask(tenant.getId(), "prueba", taskRegistrar);
});
//@TODO Falta añadir el modo multitenan
}
private void configureTask(String tenantIdentifier, String identifier, ScheduledTaskRegistrar taskRegistrar) {
Trigger trigger = new CronTrigger(cronExpression, TimeZone.getDefault());
String key = String.format("%s-%s", tenantIdentifier, identifier);
futureMap.put(key, taskRegistrar.getScheduler().schedule(() -> scheduleCron(createJob(tenantIdentifier), tenantIdentifier), trigger));
}
private Job createJob(String tenantIdentifier) {
ThreadLocalStorage.setTenantName(tenantIdentifier);
return jobBuilderFactory.get("processJob")
.incrementer(new RunIdIncrementer()).listener(listener)
.flow(createStep(tenantIdentifier)).end().build();
}
private Step createStep(String tenantIdentifier) {
ByteBotJPAWriter writer = new ByteBotJPAWriter();
writer.setService(service);
return stepBuilderFactory.get("processByteBotData").<DynaBean, DynaBean> chunk(chunk)
.reader(getReader(tenantIdentifier))
.processor(new ConvertToBeanProcessor())
.writer(writer).build();
}
private ItemReader getReader(String tenantIdentifier) {
if (properties == null) {
throw new RuntimeException("Properties not found");
}
Optional<TenantBatchBean> tenantFound = findTenant(tenantIdentifier);
if (!tenantFound.isPresent()) {
throw new RuntimeException("Properties not found");
}
Long id = eventHistoryRepository.maxEventId();
Map<String, Object> params = new HashMap<>();
params.putAll(tenantFound.get().getDatasource());
params.put("query", String.format((String) params.get("query"), id != null ? id : 0));
return dataBaseItemReaderFactory.createReader(rowMapperFactory.createMapper(new HashMap<>()), params);
}
private Optional<TenantBatchBean> findTenant(String tenantId) {
return properties.getTenants().stream().filter(x -> x.getId().equals(tenantId)).findFirst();
}
private void scheduleCron(Job job, String tenantId) {
UUID traceID = UUID.randomUUID();
Map<String, JobParameter> maps = new HashMap<>();
maps.put("time", new JobParameter(System.currentTimeMillis()));
maps.put("uuid", new JobParameter(traceID.toString()));
maps.put("tenantId", new JobParameter(tenantId));
JobParameters parameters = new JobParameters(maps);
Set<JobExecution> jobExecutions = new HashSet<>();
try {
jobExecutions = jobExplorer.findRunningJobExecutions(job.getName());
String JobInfo = String.format("Jobs {} en Ejecución: {}", job.getName(), jobExecutions.size());
log.info(JobInfo);
if (jobExecutions.isEmpty()) {
asyncJobLauncher.run(job, parameters);
} else {
log.info("El Job " + job.getName() + " no se ejecutará porque hay jobs pendientes: " + jobExecutions.size());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.bytesw.bytebot.etl.batch.writer;
import com.bytesw.bytebot.etl.batch.beans.DynaBean;
import com.bytesw.bytebot.etl.beans.EventBean;
import com.bytesw.bytebot.etl.beans.ProcessMessageResult;
import com.bytesw.bytebot.etl.services.ProcessMessageService;
import com.bytesw.xdf.multitenant.core.ThreadLocalStorage;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.item.ItemWriter;
import javax.transaction.Transactional;
import java.util.List;
@Log4j2
public class ByteBotJPAWriter implements ItemWriter<DynaBean>, StepExecutionListener {
@Getter @Setter
private ProcessMessageService service;
@Override
@Transactional
public void write(List<? extends DynaBean> list) throws Exception {
for (DynaBean dynaBean : list) {
EventBean eventBean = (EventBean) dynaBean.get("bean");
String json = (String) dynaBean.get("data");
ProcessMessageResult result = service.processMessage(json, eventBean.getSenderId());
log.debug(String.format("senderId: %s, processed: %s", eventBean.getSenderId(), result.isProcessed()));
service.saveHistory(eventBean.getId(), eventBean.getSenderId());
}
}
@Override
public void beforeStep(StepExecution stepExecution) {
String tenantId = stepExecution.getJobParameters().getString("tenantId");
ThreadLocalStorage.setTenantName(tenantId);
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return stepExecution.getExitStatus();
}
}
package com.bytesw.bytebot.etl.beans;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
@Getter @Setter @ToString
public class EventBean implements Serializable {
private Long id;
private String data;
private String senderId;
}
package com.bytesw.bytebot.etl.beans;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class ProcessMessageResult {
private boolean processed = true;
private String message;
}
package com.bytesw.bytebot.etl.beans;
import com.google.gson.annotations.Expose;
import lombok.Getter;
import lombok.Setter;
import java.sql.Timestamp;
@Getter @Setter
public class SessionBean {
@Expose
private Long id;
@Expose
private Timestamp sessionDate;
@Expose
private Timestamp lastEventDate;
@Expose
private Timestamp responseDate;
@Expose
private Long userId;
@Expose
private Long channelId;
}
package com.bytesw.bytebot.etl.config;
import com.bytesw.bytebot.etl.batch.listener.JobCompletionListener;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@Configuration
public class BatchConfig {
@Bean
public JobExecutionListener listener() {
return new JobCompletionListener();
}
@Bean("asyncJobLauncher")
public JobLauncher asyncJobLauncher(JobRepository jobRepository) {
final SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
final SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
jobLauncher.setTaskExecutor(simpleAsyncTaskExecutor);
return jobLauncher;
}
}
package com.bytesw.bytebot.etl.config;
import com.bytesw.bytebot.etl.batch.beans.TenantBatchBean;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "batch")
public class BatchProperties {
@Getter @Setter
private List<TenantBatchBean> tenants;
}
package com.bytesw.bytebot.etl.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Map;
@ConfigurationProperties(prefix = "batch")
public class BatchPropertiesWithoutTenant {
@Getter @Setter
Map<String, String> datasource;
}
package com.bytesw.bytebot.etl.converter;
import com.bytesw.bytebot.etl.enums.MessageTypeEnum;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class MessageTypeConverter implements AttributeConverter<MessageTypeEnum, String> {
@Override
public String convertToDatabaseColumn(MessageTypeEnum agentTypeEnum) {
return (agentTypeEnum != null ? agentTypeEnum.getName() : null);
}
@Override
public MessageTypeEnum convertToEntityAttribute(String s) {
return MessageTypeEnum.fromString(s);
}
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.Action;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface ActionRepository extends CrudRepository<Action, Long> {
Optional<Action> findByIdentifier(String identifier);
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.ETLChannel;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface ETLChannelRepository extends CrudRepository<ETLChannel, Long> {
Optional<ETLChannel> findByIdentifier(String identifier);
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.EventHistory;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface EventHistoryRepository extends CrudRepository<EventHistory, Long> {
@Query("SELECT MAX(e.eventId) FROM EventHistory e")
Long maxEventId();
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.Intent;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface IntentRepository extends CrudRepository<Intent, Long> {
Optional<Intent> findByIdentifier(String identifier);
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.Message;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
public interface MessageRepository extends CrudRepository<Message, Long> {
@Query("SELECT s from Message s WHERE s.sessionId = :sessionId")
Long findLastCorrelativeBySession(@Param("sessionId") Long sessionId);
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.Response;
import org.springframework.data.repository.CrudRepository;
public interface ResponseRepository extends CrudRepository<Response, Long> {
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.SessionAction;
import org.springframework.data.repository.CrudRepository;
public interface SessionActionRepository extends CrudRepository<SessionAction, Long> {
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.Session;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import java.time.OffsetDateTime;
public interface SessionBotRepository extends CrudRepository<Session, Long> {
@Query("UPDATE Session s set s.lastEventDate = :lastEventDate WHERE s.id = :id")
void updateLastEventDateBySession(@Param("id") Long id, @Param("lastEventDate") OffsetDateTime dateTime);
}
package com.bytesw.bytebot.etl.dao;
import com.bytesw.bytebot.etl.model.User;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findByIdentifier(String identifier);
}
package com.bytesw.bytebot.etl.enums;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
public enum EventTypeEnum {
USER("user"), BOT("bot"), ACTION("action"), START_SESSION("action_session_start");
private final String name;
private static final Map<String, EventTypeEnum> map = new HashMap<>();
static {
for (EventTypeEnum type : EventTypeEnum.values()) {
map.put(type.name, type);
}
}
EventTypeEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static EventTypeEnum fromString(String name) {
if (map.containsKey(name)) {
return map.get(name);
}
throw new NoSuchElementException(name + " not found");
}
}
package com.bytesw.bytebot.etl.enums;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
public enum MessageTypeEnum {
REJECTED("R"), ACCEPTED("A");
private final String name;
private static final Map<String, MessageTypeEnum> map = new HashMap<>();
static {
for (MessageTypeEnum type : MessageTypeEnum.values()) {
map.put(type.name, type);
}
}
MessageTypeEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static MessageTypeEnum fromString(String name) {
if (map.containsKey(name)) {
return map.get(name);
}
throw new NoSuchElementException(name + " not found");
}
}
package com.bytesw.bytebot.etl.jdbc;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class ETLMessageJDBCRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public int getLastCorrelativeBySession(Long sessionId) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("sessionId", sessionId);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.ETLMessageMapper.getLastCorrelativeBySession", params);
} finally {
session.close();
}
}
}
package com.bytesw.bytebot.etl.jdbc;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class ETLResponseJDBCRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public int getLastCorrelativeBySession(Long sessionId) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("sessionId", sessionId);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.ETLResponseMapper.getLastCorrelativeBySession", params);
} finally {
session.close();
}
}
}
package com.bytesw.bytebot.etl.jdbc;
import com.bytesw.bytebot.etl.beans.SessionBean;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
@Component
public class ETLSessionBotJDBCRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public SessionBean getLastSessionByUser(Long userId) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("userId", userId);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.ETLSessionMapper.getLastSessionByUser", params);
} finally {
session.close();
}
}
public void updateLastEventDate(Long sessionID, OffsetDateTime lastEventDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("sessionId", sessionID);
params.put("lastEventDate", lastEventDate);
session.update("com.bytesw.bytebot.dao.jdbc.ETLSessionMapper.updateLastEventDate", params);
} finally {
session.close();
}
}
}
package com.bytesw.bytebot.etl.model;
import com.bytesw.xdf.model.converter.BooleanToStringConverter;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_ACTION")
@NamedQuery(name = "Action.findByPK", query = "Select p from Action p where p.id = ?1")
public class Action {
@Id
@Column(name = "ACTION_ID")
@TableGenerator(name = "BBOT_ACTION_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_ACTION_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_ACTION_GENERATOR")
private Long id;
@Column(name = "ACTION_IDENT")
private String identifier;
@ManyToOne(optional = false)
@JoinColumn(name = "GOAL_ID", referencedColumnName = "GOAL_ID")
private Goal goal;
@Column(name = "ACTION_RGOAL")
@Convert(converter = BooleanToStringConverter.class)
private boolean meetGoal;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_CHANNEL_DASHBOARD")
@NamedQuery(name = "ETLChannel.findByPK", query = "Select p from ETLChannel p where p.id = ?1")
public class ETLChannel {
@Id
@Column(name = "CHANN_ID")
@TableGenerator(name = "BBOT_CHANNEL_DASHBOARD_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_CHANNEL_DASHBOARD_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_CHANNEL_DASHBOARD_GENERATOR")
private Long id;
@Column(name = "CHANN_IDENT")
private String identifier;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.OffsetDateTime;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_EVENT_HISTORY")
@NamedQuery(name = "EventHistory.findByPK", query = "Select p from EventHistory p where p.id = ?1")
public class EventHistory {
@Id
@Column(name = "EVENH_ID")
@TableGenerator(name = "BBOT_EVENT_HISTORY_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_EVENT_HISTORY_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_EVENT_HISTORY_GENERATOR")
private Long id;
@Column(name = "EVENH_SENDID")
private String senderId;
@Column(name = "EVENH_EVID")
private Long eventId;
@Column(name = "EVENH_DATE")
private OffsetDateTime date;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_GOAL")
@NamedQuery(name = "Goal.findByPK", query = "Select p from Goal p where p.id = ?1")
public class Goal {
@Id
@Column(name = "GOAL_ID")
@TableGenerator(name = "BBOT_GOAL_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_GOAL_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_GOAL_GENERATOR")
private Long id;
@Column(name = "GOAL_IDENT")
private String identifier;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
//BBOT_INTENT
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_INTENT")
@NamedQuery(name = "Intent.findByPK", query = "Select p from Intent p where p.id = ?1")
public class Intent {
@Id
@Column(name = "INTEN_ID")
@TableGenerator(name = "BBOT_INTENT_DASHBOARD_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_INTENT_DASHBOARD_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_INTENT_DASHBOARD_GENERATOR")
private Long id;
@Column(name = "INTEN_IDENT")
private String identifier;
}
package com.bytesw.bytebot.etl.model;
import com.bytesw.bytebot.etl.converter.MessageTypeConverter;
import com.bytesw.bytebot.etl.enums.MessageTypeEnum;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
@Cacheable(false)
@Entity
@Getter @Setter @ToString @Builder
@Table(name="BBOT_MESSAGE")
@NamedQuery(name = "Message.findByPK", query = "Select p from Message p where p.id = ?1")
public class Message {
@Id
@Column(name = "MESSA_ID")
@TableGenerator(name = "BBOT_MESSAGE_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_MESSAGE_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_MESSAGE_GENERATOR")
private Long id;
@Column(name = "SESSION_ID")
private Long sessionId;
@Column(name = "MESSA_DATE")
private OffsetDateTime date;
@Column(name = "MESSA_CONT")
private String content;
@Column(name = "MESSA_CORRE")
private int correlative;
@Column(name = "MESSA_PROB")
private BigDecimal probability;
@Convert(converter = MessageTypeConverter.class)
@Column(name = "MESSA_TYPE")
private MessageTypeEnum type;
@Column(name = "INTEN_ID")
private Long intentId;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.OffsetDateTime;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_RESPONSE")
@NamedQuery(name = "Response.findByPK", query = "Select p from Response p where p.id = ?1")
public class Response {
@Id
@Column(name = "RESPO_ID")
@TableGenerator(name = "BBOT_RESPONSE_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_RESPONSE_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_RESPONSE_GENERATOR")
private Long id;
@Column(name = "RESPO_DATE")
private OffsetDateTime date;
@Column(name = "RESPO_CONT")
private String content;
@Column(name = "RESPO_CORR")
private int correlative;
@Column(name = "SESSION_ID")
private Long sessionId;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.OffsetDateTime;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_SESSION")
@NamedQuery(name = "Session.findByPK", query = "Select p from Session p where p.id = ?1")
public class Session {
@Id
@Column(name = "SESSION_ID")
@TableGenerator(name = "BBOT_SESSION_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_SESSION_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_SESSION_GENERATOR")
private Long id;
@Column(name = "SESSION_DATE", nullable = false)
private OffsetDateTime sessionDate;
@Column(name = "SESSION_LEDAT", nullable = false)
private OffsetDateTime lastEventDate;
@Column(name = "SESSION_FRDAT", nullable = false)
private OffsetDateTime responseDate;
@ManyToOne
@JoinColumn(name = "CHANN_ID", referencedColumnName = "CHANN_ID")
private ETLChannel channel;
@ManyToOne(optional = false)
@JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID")
private User user;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.OffsetDateTime;
@Cacheable(false)
@Entity
@Getter @Setter @ToString
@Table(name="BBOT_ACTION_SESSION")
@NamedQuery(name = "SessionAction.findByPK", query = "Select p from SessionAction p where p.id = ?1")
public class SessionAction {
@Id
@Column(name = "ASESS_ID")
@TableGenerator(name = "BBOT_ACTION_SESSION_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_ACTION_SESSION_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_ACTION_SESSION_GENERATOR")
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "ACTION_ID", referencedColumnName = "ACTION_ID")
private Action action;
@Column(name = "ASESS_DATE")
private OffsetDateTime date;
@Column(name = "SESSION_ID")
private Long sessionId;
}
package com.bytesw.bytebot.etl.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
@Cacheable(false)
@Entity @Getter @Setter @ToString
@Table(name="BBOT_USER")
@NamedQuery(name = "User.findByPK", query = "Select p from User p where p.id = ?1")
public class User {
@Id
@Column(name = "USER_ID")
@TableGenerator(name = "BBOT_USER_GENERATOR", table = "SEQUENCE_TABLE", pkColumnName = "SEQ_NAME",
valueColumnName = "SEQ_COUNT", pkColumnValue = "BBOT_USER_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE,generator = "BBOT_USER_GENERATOR")
private Long id;
@Column(name = "USER_IDENT")
private String identifier;
}
package com.bytesw.bytebot.etl.services;
import com.bytesw.bytebot.etl.beans.SessionBean;
import com.bytesw.bytebot.etl.dao.ActionRepository;
import com.bytesw.bytebot.etl.dao.SessionActionRepository;
import com.bytesw.bytebot.etl.dao.UserRepository;
import com.bytesw.bytebot.etl.jdbc.ETLSessionBotJDBCRepository;
import com.bytesw.bytebot.etl.model.Action;
import com.bytesw.bytebot.etl.model.SessionAction;
import com.bytesw.bytebot.etl.model.User;
import com.bytesw.bytebot.etl.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.util.Optional;
@Service
@Transactional
public class ActionMessageProcessed extends MessageProcessedSupport implements MessageProcessed {
@Autowired
private ETLSessionBotJDBCRepository ETLSessionBotJDBCRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private ActionRepository actionRepository;
@Autowired
private SessionActionRepository sessionActionRepository;
@Value("${application.etl.action.user-field:sender_id}")
private String userIdentifierFieldName;
@Value("${application.etl.action.event-field:name}")
private String eventFieldName;
@PostConstruct
private void init() {
this.fields.put(SENDER_ID_FIELD_NAME, "$.sender_id");
this.fields.put(TIMESTAMP_FIELD_NAME, "$.timestamp");
this.fields.put(ACTION_FIELD_NAME, "$.name");
}
@Override
public boolean process(String json, String oldSenderId) {
String senderId = oldSenderId != null ? oldSenderId : (String) JsonUtils.getFieldFromJson(json, this.fields.get(SENDER_ID_FIELD_NAME));
if (senderId != null) {
Optional<User> userFound = userRepository.findByIdentifier(senderId);
if (!userFound.isPresent()) {
return false;
}
SessionBean session = ETLSessionBotJDBCRepository.getLastSessionByUser(userFound.get().getId());
String actionIdentifier = (String) JsonUtils.getFieldFromJson(json, this.fields.get(ACTION_FIELD_NAME));
if (session != null && actionIdentifier != null && !actionIdentifier.isEmpty()) {
Optional<Action> actionFound = actionRepository.findByIdentifier(actionIdentifier);
if (!actionFound.isPresent()) {
return false;
}
Double timestamp = (Double) JsonUtils.getFieldFromJson(json, this.fields.get(TIMESTAMP_FIELD_NAME));
SessionAction sessionAction = new SessionAction();
sessionAction.setAction(actionFound.get());
sessionAction.setSessionId(session.getId());
sessionAction.setDate(getOffsetDateTimeFromTimestampPython(timestamp));
sessionActionRepository.save(sessionAction);
updateEventDate(session.getId(), sessionAction.getDate());
return true;
}
}
return false;
}
}
package com.bytesw.bytebot.etl.services;
import com.bytesw.bytebot.etl.beans.SessionBean;
import com.bytesw.bytebot.etl.dao.ResponseRepository;
import com.bytesw.bytebot.etl.dao.UserRepository;
import com.bytesw.bytebot.etl.jdbc.ETLResponseJDBCRepository;
import com.bytesw.bytebot.etl.jdbc.ETLSessionBotJDBCRepository;
import com.bytesw.bytebot.etl.model.Response;
import com.bytesw.bytebot.etl.model.Session;
import com.bytesw.bytebot.etl.model.User;
import com.bytesw.bytebot.etl.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.time.OffsetDateTime;
import java.util.Optional;
@Service
@Transactional
public class BotMessageProcessed extends MessageProcessedSupport implements MessageProcessed {
@Autowired
private UserRepository userRepository;
@Autowired
private ETLSessionBotJDBCRepository ETLSessionBotJDBCRepository;
@Autowired
private ETLResponseJDBCRepository responseJDBCRepository;
@Autowired
private ResponseRepository responseRepository;
@PostConstruct
private void init() {
this.fields.put(SENDER_ID_FIELD_NAME, "$.sender_id");
this.fields.put(CONTENT_FIELD_NAME, "$.text");
this.fields.put(TIMESTAMP_FIELD_NAME, "$.timestamp");
}
@Override
public boolean process(String json, String oldSenderId) {
String senderId = oldSenderId != null ? oldSenderId : (String) JsonUtils.getFieldFromJson(json, this.fields.get(SENDER_ID_FIELD_NAME));
if (senderId != null) {
Optional<User> userFound = userRepository.findByIdentifier(senderId);
if (!userFound.isPresent()) {
return false;
}
SessionBean session = ETLSessionBotJDBCRepository.getLastSessionByUser(userFound.get().getId());
if (session != null) {
int correlative = responseJDBCRepository.getLastCorrelativeBySession(session.getId());
String content = (String) JsonUtils.getFieldFromJson(json, this.fields.get(CONTENT_FIELD_NAME));
Double timestamp = (Double) JsonUtils.getFieldFromJson(json, this.fields.get(TIMESTAMP_FIELD_NAME));
if (content != null && timestamp != null) {
Response response = new Response();
response.setSessionId(session.getId());
response.setCorrelative(correlative++);
response.setContent(content);
response.setDate(getOffsetDateTimeFromTimestampPython(timestamp));
responseRepository.save(response);
updateEventDate(session.getId(), response.getDate());
updateFirstResponse(session, response.getDate());
return true;
}
}
}
return false;
}
private void updateFirstResponse(SessionBean session, OffsetDateTime date) {
if (session.getResponseDate() == null) {
Optional<Session> sessionFond = sessionBotRepository.findById(session.getId());
if (sessionFond.isPresent()) {
Session sessionDB = sessionFond.get();
sessionDB.setResponseDate(date);
sessionBotRepository.save(sessionDB);
}
}
}
}
package com.bytesw.bytebot.etl.services;
@FunctionalInterface
public interface MessageProcessed {
boolean process(String json, String senderId);
}
package com.bytesw.bytebot.etl.services;
import com.bytesw.bytebot.etl.dao.SessionBotRepository;
import com.bytesw.bytebot.etl.model.Session;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class MessageProcessedSupport {
protected static final String SENDER_ID_FIELD_NAME = "senderId";
protected static final String CONTENT_FIELD_NAME = "content";
protected static final String CONFIDENCE_FIELD_NAME = "confidence";
protected static final String CHANNEL_FIELD_NAME = "channel";
protected static final String TIMESTAMP_FIELD_NAME = "timestamp";
protected static final String ACTION_FIELD_NAME = "actionName";
protected static final String INTENT_NAME = "intentName";
protected Map<String, String> fields = new HashMap<>();
@Autowired
protected SessionBotRepository sessionBotRepository;
protected static final String PYTHON_TIMESTAMP_FORMAT = "^\\d*\\.?\\d*$";
protected static final Pattern pattern = Pattern.compile(PYTHON_TIMESTAMP_FORMAT);
protected OffsetDateTime getOffsetDateTimeFromTimestampPython(Object objectTimestamp) {
BigDecimal dateDecimal;
if (objectTimestamp instanceof Double) {
dateDecimal = new BigDecimal((Double) objectTimestamp);
} else {
if (!isValidTimestampFormat(String.valueOf(objectTimestamp), pattern)) {
return null;
}
dateDecimal = new BigDecimal(String.valueOf(objectTimestamp));
}
Long timestamp = dateDecimal.longValue();
if (String.valueOf(timestamp).length() < 13) {
int numberOfZero = 13 - String.valueOf(timestamp).length();
for (int i = 0; i < numberOfZero; i++) {
timestamp = timestamp * 10;
}
}
OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
return date;
}
protected boolean isValidTimestampFormat(String text, Pattern pattern) {
Matcher matcher = pattern.matcher(text);
boolean matches = matcher.matches();
return matches;
}
protected void updateEventDate(Long sessionId, OffsetDateTime date) {
Optional<Session> sessionFond = sessionBotRepository.findById(sessionId);
if (sessionFond.isPresent()) {
Session session = sessionFond.get();
session.setLastEventDate(date);
sessionBotRepository.save(session);
}
}
}
package com.bytesw.bytebot.etl.services;
import com.bytesw.bytebot.etl.beans.ProcessMessageResult;
import com.bytesw.bytebot.etl.dao.EventHistoryRepository;
import com.bytesw.bytebot.etl.enums.EventTypeEnum;
import com.bytesw.bytebot.etl.model.EventHistory;
import com.bytesw.bytebot.etl.utils.JsonUtils;
import com.bytesw.xdf.config.AppContextManager;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.OffsetDateTime;
@Log4j2
@Service
public class ProcessMessageService {
@Autowired
private EventHistoryRepository eventHistoryRepository;
public void saveHistory(Long id, String senderId) {
EventHistory eventHistory = new EventHistory();
eventHistory.setDate(OffsetDateTime.now());
eventHistory.setEventId(id);
eventHistory.setSenderId(senderId);
eventHistoryRepository.save(eventHistory);
}
public ProcessMessageResult processMessage(String json, String senderId) throws Exception {
ProcessMessageResult result = new ProcessMessageResult();
log.debug(json);
MessageProcessed messageProcessed = detectType(json);
if (messageProcessed == null) {
result.setProcessed(false);
result.setMessage("Event type not support");
return result;
}
result.setProcessed(messageProcessed.process(json, senderId));
return result;
}
private MessageProcessed detectType(String json) {
MessageProcessed messageProcessed = null;
EventTypeEnum type;
try {
String event = (String) JsonUtils.getFieldFromJson(json, "$.event");
if (AppContextManager.getAppContext() != null && event != null) {
String name = (String) JsonUtils.getFieldFromJson(json, "$.name");
type = EventTypeEnum.fromString(event);
if (type != null) {
if (EventTypeEnum.ACTION.equals(type) && EventTypeEnum.START_SESSION.getName().equals(name)) {
type = EventTypeEnum.START_SESSION;
}
messageProcessed = (MessageProcessed) AppContextManager.getAppContext().getBean(getMessageProcessedName(type));
}
}
} catch (Exception e) {
log.debug(e);
}
return messageProcessed;
}
private String getMessageProcessedName(EventTypeEnum type) {
String[] words = type.toString().toLowerCase().split("_");
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for (String word : words) {
if (isFirst) {
sb.append(word);
isFirst = false;
} else {
sb.append(word.substring(0, 1).toUpperCase() + word.substring(1));
}
}
sb.append("MessageProcessed");
return sb.toString();
}
}
package com.bytesw.bytebot.etl.services;
import com.bytesw.bytebot.etl.dao.UserRepository;
import com.bytesw.bytebot.etl.model.Session;
import com.bytesw.bytebot.etl.model.User;
import com.bytesw.bytebot.etl.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.time.OffsetDateTime;
import java.util.Optional;
@Service
@Transactional
public class StartSessionMessageProcessed extends MessageProcessedSupport implements MessageProcessed {
@Autowired
private UserRepository userRepository;
@PostConstruct
private void init() {
this.fields.put(SENDER_ID_FIELD_NAME, "$.sender_id");
this.fields.put(TIMESTAMP_FIELD_NAME, "$.timestamp");
}
@Override
public boolean process(String json, String oldSenderId) {
String senderId = oldSenderId != null ? oldSenderId : (String) JsonUtils.getFieldFromJson(json, this.fields.get(SENDER_ID_FIELD_NAME));
if (senderId != null) {
Optional<User> userFound = userRepository.findByIdentifier(senderId);
User user;
if (!userFound.isPresent()) {
user = new User();
user.setIdentifier(senderId);
user = userRepository.save(user);
} else {
user = userFound.get();
}
Double timestamp = (Double) JsonUtils.getFieldFromJson(json, this.fields.get(TIMESTAMP_FIELD_NAME));
if (timestamp != null) {
OffsetDateTime sessionDate = getOffsetDateTimeFromTimestampPython(timestamp);
if (sessionDate != null) {
Session session = new Session();
session.setSessionDate(sessionDate);
session.setUser(user);
session.setLastEventDate(sessionDate);
sessionBotRepository.save(session);
return true;
}
}
}
return false;
}
}
package com.bytesw.bytebot.etl.services;
import com.bytesw.bytebot.etl.beans.SessionBean;
import com.bytesw.bytebot.etl.dao.ETLChannelRepository;
import com.bytesw.bytebot.etl.dao.IntentRepository;
import com.bytesw.bytebot.etl.dao.MessageRepository;
import com.bytesw.bytebot.etl.dao.UserRepository;
import com.bytesw.bytebot.etl.enums.MessageTypeEnum;
import com.bytesw.bytebot.etl.jdbc.ETLMessageJDBCRepository;
import com.bytesw.bytebot.etl.jdbc.ETLSessionBotJDBCRepository;
import com.bytesw.bytebot.etl.model.*;
import com.bytesw.bytebot.etl.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.Optional;
@Service
@Transactional
public class UserMessageProcessed extends MessageProcessedSupport implements MessageProcessed {
@Autowired
private ETLSessionBotJDBCRepository sessionBotJDBCRepository;
@Autowired
private ETLMessageJDBCRepository messageJDBCRepository;
@Autowired
private ETLChannelRepository channelRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private MessageRepository messageRepository;
@Autowired
private IntentRepository intentRepository;
@Value("${application.etl.text-user.threshold:0.5}")
private BigDecimal threshold;
@PostConstruct
private void init() {
this.fields.put(SENDER_ID_FIELD_NAME, "$.sender_id");
this.fields.put(CONFIDENCE_FIELD_NAME, "$.parse_data.intent.confidence");
this.fields.put(CONTENT_FIELD_NAME, "$.text");
this.fields.put(CHANNEL_FIELD_NAME, "$.input_channel");
this.fields.put(TIMESTAMP_FIELD_NAME, "$.timestamp");
this.fields.put(INTENT_NAME, "$.parse_data.intent.name");
}
@Override
public boolean process(String json, String oldSenderId) {
String senderId = oldSenderId != null ? oldSenderId : (String) JsonUtils.getFieldFromJson(json, this.fields.get(SENDER_ID_FIELD_NAME));
if (senderId != null) {
Optional<User> userFound = userRepository.findByIdentifier(senderId);
if (!userFound.isPresent()) {
return false;
}
SessionBean session = sessionBotJDBCRepository.getLastSessionByUser(userFound.get().getId());
if (session != null) {
Message message = cloneMessage(json, session.getId());
if (message != null) {
int correlative = messageJDBCRepository.getLastCorrelativeBySession(message.getSessionId());
correlative++;
message.setCorrelative(correlative);
messageRepository.save(message);
String channel = (String) JsonUtils.getFieldFromJson(json, this.fields.get(CHANNEL_FIELD_NAME));
updateSession(session.getId(), message.getDate(), channel);
return true;
}
}
}
return false;
}
private void updateSession(Long sessionId, OffsetDateTime date, String channelIdentifier) {
Optional<Session> sessionFond = sessionBotRepository.findById(sessionId);
if (sessionFond.isPresent()) {
Session session = sessionFond.get();
session.setLastEventDate(date);
if (channelIdentifier != null && session.getChannel() == null) {
Optional<ETLChannel> channelFound = channelRepository.findByIdentifier(channelIdentifier);
if (channelFound.isPresent()) {
session.setChannel(channelFound.get());
}
}
sessionBotRepository.save(session);
}
}
private Message cloneMessage(String json, Long sessionId) {
Double timestamp = (Double) JsonUtils.getFieldFromJson(json, this.fields.get(TIMESTAMP_FIELD_NAME));
Object confidence = JsonUtils.getFieldFromJson(json, this.fields.get(CONFIDENCE_FIELD_NAME));
String content = (String) JsonUtils.getFieldFromJson(json, this.fields.get(CONTENT_FIELD_NAME));
OffsetDateTime messageDate = getOffsetDateTimeFromTimestampPython(timestamp);
BigDecimal probability = null;
if (confidence instanceof Double) {
probability = new BigDecimal((Double) confidence);
} else if (confidence instanceof BigDecimal) {
probability = (BigDecimal) confidence;
}
if (messageDate == null || probability == null) {
return null;
}
Message message = Message.builder()
.content(content)
.sessionId(sessionId)
.date(messageDate)
.probability(new BigDecimal(String.valueOf(probability)))
.type((probability.compareTo(threshold) >= 0) ? MessageTypeEnum.ACCEPTED : MessageTypeEnum.REJECTED)
//.correlative()
.build();
if (MessageTypeEnum.ACCEPTED.equals(message.getType())) {
String intentName = (String) JsonUtils.getFieldFromJson(json, this.fields.get(INTENT_NAME));
Optional<Intent> optionalIntent = intentRepository.findByIdentifier(intentName);
if (optionalIntent.isPresent()) {
message.setIntentId(optionalIntent.get().getId());
}
}
return message;
}
}
package com.bytesw.bytebot.etl.utils;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class JsonUtils {
public static Object getFieldFromJson(String json, String jsonPath) {
Object result = null;
try {
result = JsonPath.parse(json)
.read(jsonPath);
} catch (PathNotFoundException e) {
log.debug(e);
} catch (Exception e) {
log.error(e);
}
return result;
}
}
package com.bytesw.bytebot.jdbc;
import com.bytesw.bytebot.bean.ActionSummaryByGoalBean;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class ActionJDBCRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public List<ActionSummaryByGoalBean> getSummaryByGoals(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectList("com.bytesw.bytebot.dao.jdbc.ActionMapper.getSummaryActionsByGoal", params);
} finally {
session.close();
}
}
}
package com.bytesw.bytebot.jdbc;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
@Component
public class BotSessionJDCBRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public int countSessionInRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.SessionMapper.countSessionsInRange", params);
} finally {
session.close();
}
}
public Timestamp getLastDateInRage(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.SessionMapper.getLastDateInRange", params);
} finally {
session.close();
}
}
public Double getAvgSessionByCustomerInRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.SessionMapper.avgSessionsByCustomerInRange", params);
} finally {
session.close();
}
}
public Double getAvgFirstResponseTime(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.SessionMapper.avgFirstResponseTime", params);
} finally {
session.close();
}
}
}
package com.bytesw.bytebot.jdbc;
import com.bytesw.bytebot.bean.MessageByIntentBean;
import com.bytesw.bytebot.bean.SummaryMessageByIntentBean;
import com.bytesw.bytebot.bean.SummaryMessageBySentenceBean;
import com.bytesw.xdf.sql.beans.Pagination;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class MessageJDBCRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public int countSessionInRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countMessagesInRange", params);
} finally {
session.close();
}
}
public int countMessageInRangeHour(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countMessagesInRangeForHour", params);
} finally {
session.close();
}
}
public List<SummaryMessageBySentenceBean> getSummaryByIntentAndSentence(Pagination<SummaryMessageBySentenceBean> pagination) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("initLimit", pagination.getCurrentPage() * pagination.getItemsPerPage());
params.put("itemsForPage", pagination.getItemsPerPage());
if (pagination.getSortFields() != null && pagination.getSortFields().length > 0) {
params.put("columnSort", pagination.getSortFields()[0].getField());
params.put("directionSort", pagination.getSortFields()[0].getDirection().toUpperCase());
} else {
params.put("columnSort", "count");
params.put("directionSort", "DESC");
}
completeDates(params, pagination.getFilterExpression());
//params.put("startDate", startDate);
//params.put("endDate", endDate);
return session.selectList("com.bytesw.bytebot.dao.jdbc.MessageMapper.getSummaryByIntentAndSentence", params);
} finally {
session.close();
}
}
public List<SummaryMessageByIntentBean> getSummaryByIntent(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectList("com.bytesw.bytebot.dao.jdbc.MessageMapper.getSummaryByIntent", params);
} finally {
session.close();
}
}
/**
* Metodo que consulta el total de mensajes con intent asociado
* @return
*/
public int countByIntentAndRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countByIntentAndRange", params);
} finally {
session.close();
}
}
/**
* Metodo que consulta el total de frases sin intent asociado
* @return
*/
public int countBySentencesAndRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countBySentencesAndRange", params);
} finally {
session.close();
}
}
public List<SummaryMessageBySentenceBean> getSummaryBySentence(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
params.put("initLimit", 0);
params.put("itemsForPage", 4);
params.put("columnSort", "count");
params.put("directionSort", "DESC");
return session.selectList("com.bytesw.bytebot.dao.jdbc.MessageMapper.getSummaryBySentence", params);
} finally {
session.close();
}
}
public List<SummaryMessageBySentenceBean> getMessageBySentencePage(Pagination<SummaryMessageBySentenceBean> pagination) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("initLimit", pagination.getCurrentPage() * pagination.getItemsPerPage());
params.put("itemsForPage", pagination.getItemsPerPage());
if (pagination.getSortFields() != null && pagination.getSortFields().length > 0) {
params.put("columnSort", pagination.getSortFields()[0].getField());
params.put("directionSort", pagination.getSortFields()[0].getDirection().toUpperCase());
} else {
params.put("columnSort", "count");
params.put("directionSort", "DESC");
}
completeDates(params, pagination.getFilterExpression());
return session.selectList("com.bytesw.bytebot.dao.jdbc.MessageMapper.getSummaryBySentence", params);
} finally {
session.close();
}
}
public int countSummaryBySentence(Pagination<SummaryMessageBySentenceBean> pagination) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
completeDates(params, pagination.getFilterExpression());
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countSummaryBySentence", params);
} finally {
session.close();
}
}
/**
* obtiene el promedio intenciones por cliente y rango de fechas
* @return
*/
public Double avgIntentsByCustomerAndRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.avgIntentsByCustomerAndRange", params);
} finally {
session.close();
}
}
/**
* Obtiene la cantidad por cada intención en un periodo de tiempo
* @return
*/
public List<MessageByIntentBean> countMessageByIntent(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectList("com.bytesw.bytebot.dao.jdbc.MessageMapper.countMessageByIntent", params);
} finally {
session.close();
}
}
public int countSummaryByIntentAndSentence(Pagination<SummaryMessageBySentenceBean> pagination) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
completeDates(params, pagination.getFilterExpression());
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countSummaryByIntentAndSentence", params);
} finally {
session.close();
}
}
public int countCustomersBySentence(String sentence) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("sentence", sentence);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.MessageMapper.countCustomersBySentence", params);
} finally {
session.close();
}
}
private void completeDates(Map<String, Object> params, String filterString) {
if (filterString == null || filterString.isEmpty()) {
return;
}
String[] filters = filterString.split("&&");
if (filters != null) {
for (String filter : filters) {
String[] filterValue = filter.split("=");
params.put(filterValue[0], OffsetDateTime.ofInstant(Instant.ofEpochMilli(new Long(filterValue[1])), ZoneId.systemDefault()));
}
}
}
}
package com.bytesw.bytebot.jdbc;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
@Component
public class ResponseJDBCRepository {
@Autowired
@Qualifier("sqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;
public int countSessionInRange(OffsetDateTime startDate, OffsetDateTime endDate) {
SqlSession session = sqlSessionFactory.openSession();
try {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return session.selectOne("com.bytesw.bytebot.dao.jdbc.ResponseMapper.countMessagesInRange", params);
} finally {
session.close();
}
}
}
package com.bytesw.bytebot.routes; package com.bytesw.bytebot.routes;
import com.bytesw.xdf.multitenant.core.ThreadLocalStorage;
import org.apache.camel.builder.RouteBuilder; import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -22,10 +23,20 @@ public class SFTPRoute extends RouteBuilder { ...@@ -22,10 +23,20 @@ public class SFTPRoute extends RouteBuilder {
@Value("${application.bytebot-integration.ftp.passiveMode:true}") @Value("${application.bytebot-integration.ftp.passiveMode:true}")
private boolean passiveMode; private boolean passiveMode;
@Value("${application.services.multi-tenant:false}")
private boolean multitenant;
@Override @Override
public void configure() throws Exception { public void configure() throws Exception {
from("direct:transferFile") from("direct:transferFile")
.toF("ftp://%s@%s/%s?password=%s&binary=true&passiveMode=%s", username, host, directory, password, passiveMode) .toF("ftp://%s@%s/%s?password=%s&binary=true&passiveMode=%s", username, host, getDirectory(), password, passiveMode)
.log("Transfered file .${file:name} "); .log("Transfered file .${file:name} ");
} }
private String getDirectory() {
if (!multitenant || ThreadLocalStorage.getTenantName() == null) {
return directory;
}
return ThreadLocalStorage.getTenantName() + "/" + directory;
}
} }
package com.bytesw.bytebot.service.dashboard;
import com.bytesw.bytebot.bean.*;
import com.bytesw.bytebot.jdbc.ActionJDBCRepository;
import com.bytesw.bytebot.jdbc.MessageJDBCRepository;
import com.bytesw.xdf.sql.beans.Pagination;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class CustomerInteractionDashboardService extends DashboardService {
@Autowired
private MessageJDBCRepository messageJDBCRepository;
@Autowired
private ActionJDBCRepository actionJDBCRepository;
@Override
protected void completeData(OffsetDateTime startDate, OffsetDateTime endDate, Map<String, Object> info) {
List<RangeBean> rangeList = calculateRangeList(startDate, endDate);
info.put("sessionFlow", generateInteractionByCustomerData(startDate, endDate));
info.put("summaryGoals", generateSummaryByGoals(startDate, endDate));
info.put("intentAvgByCustomer", generateAverageIntentsByCustomer(rangeList));
info.put("summaryIntents", generateSummaryMessageByIntent(rangeList));
}
private List<ActionSummaryByGoalBean> generateSummaryByGoals(OffsetDateTime startDate, OffsetDateTime endDate) {
List<ActionSummaryByGoalBean> actionByGoalList;
actionByGoalList = actionJDBCRepository.getSummaryByGoals(startDate, endDate);
if (actionByGoalList == null) {
actionByGoalList = new ArrayList<>();
}
return actionByGoalList;
}
private Map<String, List<Object>> generateSummaryMessageByIntent(List<RangeBean> rangeList) {
Map<String, List<Object>> data = new HashMap<>();
rangeList.stream().forEach(x -> {
List<MessageByIntentBean> list = messageJDBCRepository.countMessageByIntent(x.getStartDate(), x.getEndDate());
list.stream().forEach(intentSummary -> {
if (!data.containsKey(intentSummary.getIdentifier())){
data.put(intentSummary.getIdentifier(), new ArrayList<>());
}
data.get(intentSummary.getIdentifier()).add(new Object[]{getDayOnStart(x.getStartDate()).toInstant().toEpochMilli()/1000, intentSummary.getCount()});
});
});
return data;
}
private List<Double> generateAverageIntentsByCustomer(List<RangeBean> rangeList) {
List<Double> averageList = new ArrayList<>();
rangeList.stream().forEach(x -> {
Double avg = messageJDBCRepository.avgIntentsByCustomerAndRange(x.getStartDate(), x.getEndDate());
averageList.add(avg != null ? round(avg) : Double.valueOf(0));
});
return averageList;
}
private double round(Double value) {
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(2, RoundingMode.HALF_UP);
return bd.doubleValue();
}
private Map<String, Map<String, Object>> generateInteractionByCustomerData(OffsetDateTime startDate, OffsetDateTime endDate) {
Map<String, Map<String, Object>> data = new HashMap<>();
data.put("intent", new HashMap<>());
List<SummaryMessageByIntentBean> intentTopList = messageJDBCRepository.getSummaryByIntent(startDate, endDate);
int totalIntents = messageJDBCRepository.countByIntentAndRange(startDate, endDate);
if (intentTopList == null) {
new ArrayList<>();
}
BigInteger result = intentTopList.stream()
.map(SummaryMessageByIntentBean::getCount)
.reduce(BigInteger.ZERO, BigInteger::add);
SummaryMessageByIntentBean others = new SummaryMessageByIntentBean();
others.setCount(new BigInteger(String.valueOf(totalIntents)).subtract(result));
others.setId(0L);
others.setIdentifier("others");
intentTopList.add(others);
data.get("intent").put("total", totalIntents);
data.get("intent").put("topList", intentTopList);
List<SummaryMessageBySentenceBean> sentenceTopList = messageJDBCRepository.getSummaryBySentence(startDate, endDate);
int totalSentences = messageJDBCRepository.countBySentencesAndRange(startDate, endDate);
if (sentenceTopList == null) {
sentenceTopList = new ArrayList<>();
}
data.put("sentence", new HashMap<>());
BigInteger resultSentence = sentenceTopList.stream()
.map(SummaryMessageBySentenceBean::getCount)
.reduce(BigInteger.ZERO, BigInteger::add);
SummaryMessageBySentenceBean othersSentence = new SummaryMessageBySentenceBean();
othersSentence.setCount(new BigInteger(String.valueOf(totalSentences)).subtract(resultSentence));
othersSentence.setId(0L);
othersSentence.setIdentifier("others");
sentenceTopList.add(othersSentence);
data.get("sentence").put("topList", sentenceTopList);
data.get("sentence").put("total", totalSentences);
return data;
}
public void getSummaryByIntentAndSentencePagination(Pagination<SummaryMessageBySentenceBean> pagination) {
int total = messageJDBCRepository.countSummaryByIntentAndSentence(pagination);
int totalPages = total / pagination.getItemsPerPage();
if (total % pagination.getItemsPerPage() != 0) {
totalPages++;
}
pagination.setTotalItems(total);
pagination.setTotalPages(totalPages);
List<SummaryMessageBySentenceBean> list = messageJDBCRepository.getSummaryByIntentAndSentence(pagination);
list.stream().forEach(x -> {
int customers = messageJDBCRepository.countCustomersBySentence(x.getSentence());
x.setCustomerCount(BigInteger.valueOf(customers));
});
pagination.setData(list);
}
public void getSummaryBySentencePagination(Pagination<SummaryMessageBySentenceBean> pagination) {
int total = messageJDBCRepository.countSummaryBySentence(pagination);
int totalPages = total / pagination.getItemsPerPage();
if (total % pagination.getItemsPerPage() != 0) {
totalPages++;
}
pagination.setTotalItems(total);
pagination.setTotalPages(totalPages);
List<SummaryMessageBySentenceBean> list = messageJDBCRepository.getMessageBySentencePage(pagination);
pagination.setData(list);
}
}
package com.bytesw.bytebot.service.dashboard;
import com.bytesw.bytebot.bean.RangeBean;
import lombok.extern.log4j.Log4j2;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Log4j2
public abstract class DashboardService {
abstract void completeData(OffsetDateTime startDate, OffsetDateTime endDate, Map<String, Object> info);
public Map<String, Object> generateInfo(Map<String, Object> params) {
Map<String, Object> info = new HashMap<>();
if (params == null) {
return info;
}
OffsetDateTime startDate = convertToOffsetDatetime((String) params.get("startDate"));
OffsetDateTime endDate = convertToOffsetDatetime((String) params.get("endDate"));
if (startDate == null || endDate == null) {
return info;
}
this.completeData(startDate, endDate, info);
return info;
}
protected OffsetDateTime convertToOffsetDatetime(String date) {
if (date.length() == 24) {
date = date.substring(0, date.length() - 1);
}
OffsetDateTime dateOffset = null;
try {
LocalDateTime dateParsed = LocalDateTime.parse(date);
dateOffset = OffsetDateTime.ofInstant(dateParsed.toInstant(ZoneOffset.UTC), ZoneId.systemDefault());
} catch (Exception e) {
log.warn(e);
}
return dateOffset;
}
protected OffsetDateTime getNextHour(OffsetDateTime date) {
OffsetDateTime nextDate = date.plusHours(1);
nextDate = nextDate.withMinute(0);
nextDate = nextDate.withSecond(0);
nextDate = nextDate.withNano(0);
return nextDate;
}
protected OffsetDateTime getNextDay(OffsetDateTime date) {
OffsetDateTime newDate = date.plusDays(1);
newDate = newDate.withSecond(0);
newDate = newDate.withMinute(0);
newDate = newDate.withHour(0);
newDate = newDate.withNano(0);
return newDate;
}
protected OffsetDateTime getDayOnStart(OffsetDateTime date) {
OffsetDateTime nextDate = date.withHour(12);
nextDate = nextDate.withMinute(0);
nextDate = nextDate.withSecond(0);
nextDate = nextDate.withNano(0);
return nextDate;
}
protected List<RangeBean> calculateRangeList(OffsetDateTime startDate, OffsetDateTime endDate) {
OffsetDateTime nextDate = getNextDay(startDate);
OffsetDateTime startNextDate = startDate;
List<RangeBean> rangeList = new ArrayList<>();
while (nextDate.isBefore(endDate)) {
RangeBean rangeBean = new RangeBean();
rangeBean.setStartDate(startNextDate);
rangeBean.setEndDate(nextDate);
rangeList.add(rangeBean);
startNextDate = nextDate;
nextDate = getNextDay(nextDate);
}
RangeBean rangeBean = new RangeBean();
rangeBean.setStartDate(startNextDate);
rangeBean.setEndDate(endDate);
rangeList.add(rangeBean);
return rangeList;
}
}
package com.bytesw.bytebot.service.dashboard;
import com.bytesw.bytebot.bean.AverageBean;
import com.bytesw.bytebot.bean.RangeBean;
import com.bytesw.bytebot.bean.SummaryBean;
import com.bytesw.bytebot.jdbc.BotSessionJDCBRepository;
import com.bytesw.bytebot.jdbc.MessageJDBCRepository;
import com.bytesw.bytebot.jdbc.ResponseJDBCRepository;
import com.bytesw.xdf.exception.NotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class OperativeDashboardService extends DashboardService {
@Autowired
private BotSessionJDCBRepository botSessionJDCBRepository;
@Autowired
private MessageJDBCRepository messageJDBCRepository;
@Autowired
private ResponseJDBCRepository responseJDBCRepository;
@Override
protected void completeData(OffsetDateTime startDate, OffsetDateTime endDate, Map<String, Object> info) {
List<RangeBean> rangeList = calculateRangeList(startDate, endDate);
List<Object[]> messageByActivity = generateData(rangeList);
//Cantidad de sesiones
int cantSessions = botSessionJDCBRepository.countSessionInRange(startDate, endDate);
int cantReceivedMessages = messageJDBCRepository.countSessionInRange(startDate, endDate);
int cantResponseMessages = responseJDBCRepository.countSessionInRange(startDate, endDate);
//Promedio primera respuesta en mili
Double avgFirstResponse = botSessionJDCBRepository.getAvgFirstResponseTime(startDate, endDate);
Double avgSessionsByCustomer = botSessionJDCBRepository.getAvgSessionByCustomerInRange(startDate, endDate);
Timestamp timestamp = botSessionJDCBRepository.getLastDateInRage(startDate, endDate);
if (timestamp == null) {
throw new NotFoundException("No se encontró una sesión en el rango de fechas indicado");
}
//Calculando el tiempo de inactividad de la sesion
OffsetDateTime lastSessionDate = OffsetDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault());
Duration difference = Duration.between(lastSessionDate, endDate);
SummaryBean sessionInactivity = new SummaryBean();
sessionInactivity.setValue(new BigInteger(String.valueOf(difference.getSeconds())));
sessionInactivity.setHistory(new ArrayList<>());
sessionInactivity.setPercent(new BigDecimal("1.2"));
sessionInactivity.getHistory().add(new BigInteger("10"));
sessionInactivity.getHistory().add(new BigInteger("10"));
sessionInactivity.getHistory().add(new BigInteger("10"));
sessionInactivity.getHistory().add(new BigInteger("10"));
sessionInactivity.getHistory().add(new BigInteger("10"));
SummaryBean totalSessions = new SummaryBean();
totalSessions.setValue(new BigInteger(String.valueOf(cantSessions)));
totalSessions.setHistory(new ArrayList<>());
totalSessions.setPercent(new BigDecimal("1.2"));
totalSessions.getHistory().add(new BigInteger("2"));
totalSessions.getHistory().add(new BigInteger("4"));
totalSessions.getHistory().add(new BigInteger("6"));
totalSessions.getHistory().add(new BigInteger("8"));
totalSessions.getHistory().add(new BigInteger("10"));
SummaryBean totalReceivedMessages = new SummaryBean();
totalReceivedMessages.setValue(new BigInteger(String.valueOf(cantReceivedMessages)));
totalReceivedMessages.setHistory(new ArrayList<>());
totalReceivedMessages.setPercent(new BigDecimal("1.2"));
totalReceivedMessages.getHistory().add(new BigInteger("10"));
totalReceivedMessages.getHistory().add(new BigInteger("8"));
totalReceivedMessages.getHistory().add(new BigInteger("6"));
totalReceivedMessages.getHistory().add(new BigInteger("8"));
totalReceivedMessages.getHistory().add(new BigInteger("10"));
SummaryBean totalSentMessages = new SummaryBean();
totalSentMessages.setValue(new BigInteger(String.valueOf(cantResponseMessages)));
totalSentMessages.setHistory(new ArrayList<>());
totalSentMessages.setPercent(new BigDecimal("1.2"));
totalSentMessages.getHistory().add(new BigInteger("2"));
totalSentMessages.getHistory().add(new BigInteger("5"));
totalSentMessages.getHistory().add(new BigInteger("10"));
totalSentMessages.getHistory().add(new BigInteger("5"));
totalSentMessages.getHistory().add(new BigInteger("2"));
Map<String, Object> summary = new HashMap<>();
summary.put("sessionInactivity", sessionInactivity);
summary.put("totalSessions", totalSessions);
summary.put("totalReceivedMessages", totalReceivedMessages);
summary.put("totalSentMessages", totalSentMessages);
AverageBean averageBean = new AverageBean();
if (avgFirstResponse == null) {
averageBean.setFirstResponseAverage(new BigDecimal(0));
} else {
averageBean.setFirstResponseAverage(new BigDecimal(avgFirstResponse));
}
averageBean.setSessionAverage(new BigDecimal(avgSessionsByCustomer));
info.put("summary", summary);
info.put("averages", averageBean);
info.put("customerMessageDetail", messageByActivity);
}
private List<Object[]> generateData(List<RangeBean> rangeList) {
List<Object[]> data = new ArrayList<>();
Map<Long, Map<Integer, Integer>> accumulated = new HashMap<>();
for (RangeBean range : rangeList) {
List<RangeBean> hourRanges = getRangeHours(range.getStartDate(), range.getEndDate());
for (RangeBean hourRange : hourRanges) {
int cant = messageJDBCRepository.countMessageInRangeHour(hourRange.getStartDate(), hourRange.getEndDate());
int rangeHour = getRangeHour(hourRange.getStartDate().getHour());
Long timestamp = getTimestamp(hourRange.getStartDate());
if (!accumulated.containsKey(timestamp)) {
accumulated.put(timestamp, new HashMap<>());
}
if (!accumulated.get(timestamp).containsKey(rangeHour)) {
accumulated.get(timestamp).put(rangeHour, 0);
}
accumulated.get(timestamp).put(rangeHour, accumulated.get(timestamp).get(rangeHour) + cant);
}
}
accumulated.keySet().stream().forEach(x -> {
accumulated.get(x).keySet().stream().forEach(y -> {
data.add(new Object[]{x, y, accumulated.get(x).get(y)});
});
});
return data;
}
private int getRangeHour(int hour) {
switch (hour) {
case 3:
case 4:
case 5:
return 1;
case 6:
case 7:
case 8:
return 2;
case 9:
case 10:
case 11:
return 3;
case 12:
case 13:
case 14:
return 4;
case 15:
case 16:
case 17:
return 5;
case 18:
case 19:
case 20:
return 6;
case 21:
case 22:
case 23:
return 7;
default:
return 0;
}
}
private long getTimestamp(OffsetDateTime date) {
OffsetDateTime dateTime;
dateTime = date.withHour(0);
dateTime = dateTime.withMinute(0);
dateTime = dateTime.withSecond(0);
dateTime = dateTime.withNano(0);
return dateTime.toInstant().toEpochMilli();
}
private List<RangeBean> getRangeHours(OffsetDateTime startDate, OffsetDateTime endDate) {
OffsetDateTime nextDate = getNextHour(startDate);
OffsetDateTime startNextDate = startDate;
List<RangeBean> rangeList = new ArrayList<>();
while (nextDate.isBefore(endDate)) {
RangeBean rangeBean = new RangeBean();
rangeBean.setStartDate(startNextDate);
rangeBean.setEndDate(nextDate);
rangeList.add(rangeBean);
startNextDate = nextDate;
nextDate = getNextHour(nextDate);
}
if (startNextDate.isBefore(endDate)) {
RangeBean rangeBean = new RangeBean();
rangeBean.setStartDate(startNextDate);
rangeBean.setEndDate(endDate);
rangeList.add(rangeBean);
}
return rangeList;
}
}
...@@ -24,6 +24,10 @@ management: ...@@ -24,6 +24,10 @@ management:
web.exposure.include: "*" web.exposure.include: "*"
application: application:
byte-bot:
batch:
chunk: 1
cron: 0/5 * * * * *
show-side-bar: false show-side-bar: false
test: ENC(OEchnTXpIZnCVdPNthgCZBfQjMt1AUS1) test: ENC(OEchnTXpIZnCVdPNthgCZBfQjMt1AUS1)
name: xdf-example name: xdf-example
...@@ -48,8 +52,10 @@ application: ...@@ -48,8 +52,10 @@ application:
license: 'Open source licensing' license: 'Open source licensing'
license-url: 'https://help.github.com/articles/open-source-licensing/' license-url: 'https://help.github.com/articles/open-source-licensing/'
services: services:
authorization-service.url: http://localhost:7580 multi-tenant-conf:
security: oauth2sso # none, basic, oauth2sso exclude-service: /health
authorization-service.url: none
security: none # none, basic, oauth2sso
security.method: true security.method: true
security-exclude: /service/oauth/userinfo, /actuator/**, /mylogout, /login, /logout, /goodbye, /error, /anon, /cache.manifest, /favicon.ico, /service/file, /goodbye security-exclude: /service/oauth/userinfo, /actuator/**, /mylogout, /login, /logout, /goodbye, /error, /anon, /cache.manifest, /favicon.ico, /service/file, /goodbye
messaging: messaging:
...@@ -97,11 +103,11 @@ spring: ...@@ -97,11 +103,11 @@ spring:
datasource: datasource:
database-type: mysql database-type: mysql
schemaName: BYTEBOT_BASE schemaName: bbot_t186a1
url: jdbc:mysql://localhost:3306/BYTEBOT_BASE?useSSL=false url: jdbc:postgresql://localhost:5432/bbot_t186a1?useSSL=false
driverClassName: 'com.mysql.cj.jdbc.Driver' driverClassName: 'org.postgresql.Driver'
username: root username: postgres
password: secret password: root
minimum-idle: 10 minimum-idle: 10
maximum-pool-size: 10 maximum-pool-size: 10
validationQuery: SELECT 1 validationQuery: SELECT 1
...@@ -112,9 +118,9 @@ spring: ...@@ -112,9 +118,9 @@ spring:
id: T186A1 id: T186A1
servername: cdb.bytebot.t186a1 servername: cdb.bytebot.t186a1
datasource: datasource:
url: jdbc:mysql://localhost:3306/BYTEBOT_T186A1 url: jdbc:postgresql://localhost:5432/bbot_t186a1?useSSL=false
username: root username: postgres
password: secret password: root
minimum-idle: 10 minimum-idle: 10
maximum-pool-size: 100 maximum-pool-size: 100
validationQuery: SELECT 1 validationQuery: SELECT 1
...@@ -131,40 +137,31 @@ spring: ...@@ -131,40 +137,31 @@ spring:
oauth2-resource: oauth2-resource:
userInfoUri: http://cdb.bytebot.sso:8080/oauth/userinfo userInfoUri: http://cdb.bytebot.sso:8080/oauth/userinfo
logoutUri: http://cdb.bytebot.sso:8080/oauth/userlogout logoutUri: http://cdb.bytebot.sso:8080/oauth/userlogout
-
id: T186A2
servername: cdb.bytebot.local
datasource:
url: jdbc:mysql://localhost:3306/BYTEBOT_T186A2
username: root
password: secret
minimum-idle: 10
maximum-pool-size: 100
validationQuery: SELECT 1
testWhileIdle: true
hikari.registerMbeans: true
security:
basepath: http://cdb.bytebot.local:9077/bytebot
provider: byte # oracle, amazon
oauth2-client:
clientId: xdf-client
clientSecret: xdf-secret
accessTokenUri: http://cdb.bytebot.sso:8080/oauth/token
userAuthorizationUri: http://cdb.bytebot.sso:8080/oauth/authorize
oauth2-resource:
userInfoUri: http://cdb.bytebot.sso:8080/oauth/userinfo
logoutUri: http://cdb.bytebot.sso:8080/oauth/userlogout
jpa: jpa:
open-in-view: false open-in-view: false
properties.hibernate: properties.hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect dialect: org.hibernate.dialect.PostgreSQL9Dialect
format_sql: false format_sql: false
hbm2ddl.auto: none hbm2ddl.auto: none
jdbc:
lob:
non_contextual_creation: true
show-sql: true show-sql: true
#session.store-type: jdbc #session.store-type: jdbc
activemq.broker-url: tcp://localhost:61616 activemq.broker-url: tcp://localhost:61616
batch:
tenants:
-
id: T186A1
datasource:
jdbc-driver: org.postgresql.Driver
username: postgres
password: ByNV8alhJURethztAMOc
jdbc-url: jdbc:postgresql://bytebothdi.crvfvdkyambz.us-east-1.rds.amazonaws.com:5432/bytebot_hdi_db_core
query: 'select * from events WHERE id > %d order by id asc'
logging.level.root: INFO logging.level.root: INFO
logging.pattern.console: '%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n' logging.pattern.console: '%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n'
...@@ -181,8 +178,8 @@ logging.level.com.github.alturkovic.lock: ERROR ...@@ -181,8 +178,8 @@ logging.level.com.github.alturkovic.lock: ERROR
logging.level.com.ulisesbocchio.jasyptspringboot: ERROR logging.level.com.ulisesbocchio.jasyptspringboot: ERROR
logging.level.org.hibernate.SQL: TRACE #logging.level.org.hibernate.SQL: TRACE
logging.level.org.hibernate.type: TRACE #logging.level.org.hibernate.type: TRACE
logging.level.net.sf.hibernate.type: TRACE #logging.level.net.sf.hibernate.type: TRACE
jasypt.encryptor.password: 179CD78D24F9BC63D6E677272D1A7 jasypt.encryptor.password: 179CD78D24F9BC63D6E677272D1A7
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ActionMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getSummaryActionsByGoal" resultType="ActionSummaryByGoal" flushCache="true">
SELECT COUNT(BAS.ASESS_ID) as count,
G.GOAL_IDENT as goal
FROM BBOT_ACTION_SESSION BAS
LEFT JOIN BBOT_ACTION A ON BAS.ACTION_ID = A.ACTION_ID
LEFT JOIN BBOT_GOAL G ON G.GOAL_ID = A.GOAL_ID
WHERE A.ACTION_RGOAL = 'Y'
AND BAS.ASESS_DATE &lt;= #{endDate} AND BAS.ASESS_DATE &gt;= #{startDate}
GROUP BY G.GOAL_ID
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.MessageMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="countMessagesInRange" resultType="int" flushCache="true">
SELECT COUNT(MESSA_ID)
FROM BBOT_MESSAGE
WHERE MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<select id="countMessagesInRangeForHour" resultType="int" flushCache="true">
SELECT COUNT(MESSA_ID)
FROM BBOT_MESSAGE
WHERE MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<!-- @TODO Pendiente agregar la fecha -->
<select id="getSummaryByIntentAndSentence" resultType="SummaryMessageBySentence" flushCache="true">
SELECT
DISTINCT(MESSA_CONT) as sentence,
COUNT(MESSA_ID) AS count,
I.INTEN_IDENT as identifier,
I.INTEN_ID as id
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL
AND M.MESSA_DATE &lt;= #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY M.MESSA_CONT, I.INTEN_ID
ORDER BY ${columnSort} ${directionSort} LIMIT ${initLimit},${itemsForPage}
</select>
<select id="countSummaryByIntentAndSentence" resultType="int" flushCache="true">
select count(*) FROM (SELECT
DISTINCT(MESSA_CONT) as sentence,
COUNT(MESSA_ID) AS count,
I.INTEN_IDENT as identifier,
I.INTEN_ID as id
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL
AND M.MESSA_DATE &lt;= #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY M.MESSA_CONT, I.INTEN_ID
ORDER BY count DESC) as BBOT_SUMMARY
</select>
<select id="getSummaryByIntent" resultType="SummaryMessageByIntent" flushCache="true">
SELECT COUNT(MESSA_ID) AS count,
I.INTEN_IDENT as identifier,
I.INTEN_ID as id
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
GROUP BY I.INTEN_ID
ORDER BY count DESC LIMIT 4
</select>
<select id="getSummaryBySentence" resultType="SummaryMessageBySentence" flushCache="true">
SELECT
COUNT(MESSA_ID) as count,
MESSA_CONT as identifier
FROM BBOT_MESSAGE M
WHERE INTEN_ID IS NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
GROUP BY MESSA_CONT
ORDER BY ${columnSort} ${directionSort}, identifier DESC LIMIT ${initLimit},${itemsForPage}
</select>
<select id="countSummaryBySentence" resultType="int" flushCache="true">
SELECT count(*) FROM (SELECT
COUNT(MESSA_ID) as count,
MESSA_CONT as identifier
FROM BBOT_MESSAGE M
WHERE INTEN_ID IS NULL
AND M.MESSA_DATE &lt;= #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY MESSA_CONT
ORDER BY count DESC, identifier DESC) as BBOT_SUMMARY
</select>
<select id="countByIntentAndRange" resultType="int" flushCache="true">
SELECT
COUNT(MESSA_ID)
FROM BBOT_MESSAGE
WHERE INTEN_ID IS NOT NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<select id="countBySentencesAndRange" resultType="int" flushCache="true">
SELECT
COUNT(MESSA_ID)
FROM BBOT_MESSAGE WHERE INTEN_ID IS NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<select id="avgIntentsByCustomerAndRange" resultType="Double" flushCache="true">
SELECT AVG (COUNT_MESSA) FROM
(
SELECT COUNT(MESSA_ID) as COUNT_MESSA,
S.USER_ID
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_SESSION S ON M.SESSION_ID = S.SESSION_ID
WHERE M.INTEN_ID IS NOT NULL AND M.MESSA_DATE &lt; #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY S.USER_ID
) BBOT_INTENT_CUSTOMER
</select>
<select id="countMessageByIntent" resultType="MessageByIntent" flushCache="true">
SELECT
COUNT(M.MESSA_ID) as count,
I.INTEN_IDENT as identifier
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL AND M.MESSA_DATE &lt; #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY I.INTEN_IDENT
</select>
<select id="countCustomersBySentence" resultType="Double" flushCache="true">
SELECT COUNT(distinct USER_ID)
FROM BBOT_SESSION
WHERE SESSION_ID in (select DISTINCT SESSION_ID from BBOT_MESSAGE bm WHERE MESSA_CONT = #{sentence})
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ResponseMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="countMessagesInRange" resultType="int" flushCache="true">
SELECT COUNT(RESPO_ID)
FROM BBOT_RESPONSE
WHERE RESPO_DATE &lt;= #{endDate} AND RESPO_DATE &gt;= #{startDate}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.SessionMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastDateInRange" resultType="java.sql.Timestamp" flushCache="true">
select SESSION_LEDAT
FROM BBOT_SESSION bas
WHERE SESSION_LEDAT &lt;= #{endDate}
AND SESSION_LEDAT &gt;= #{startDate}
ORDER BY SESSION_LEDAT DESC LIMIT 1
</select>
<select id="countSessionsInRange" resultType="int" flushCache="true">
select COUNT(SESSION_ID)
FROM BBOT_SESSION bas
WHERE SESSION_DATE &lt;= #{endDate}
AND SESSION_DATE &gt;= #{startDate}
</select>
<select id="avgSessionsByCustomerInRange" resultType="Double" flushCache="true">
select avg(SESSION_CANT) FROM
(
select count(USER_ID) as SESSION_CANT
from BBOT_SESSION bas
WHERE SESSION_DATE &lt;= #{endDate} AND SESSION_DATE &gt;= #{startDate} GROUP BY USER_ID
) BBOT_SESSION_COUNT
</select>
<select id="avgFirstResponseTime" resultType="Long" flushCache="true">
SELECT AVG(RESP_TIME)
FROM (
select TIMESTAMPDIFF(SECOND, SESSION_DATE, SESSION_FRDAT) AS RESP_TIME
from BBOT_SESSION bs WHERE SESSION_FRDAT IS NOT NULL
AND SESSION_DATE &lt;= #{endDate}
AND SESSION_DATE &gt;= #{startDate}
) RESPONSE_DIF
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ActionMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getSummaryActionsByGoal" resultType="ActionSummaryByGoal" flushCache="true">
SELECT COUNT(BAS.ASESS_ID) as count,
G.GOAL_IDENT as goal
FROM BBOT_ACTION_SESSION BAS
LEFT JOIN BBOT_ACTION A ON BAS.ACTION_ID = A.ACTION_ID
LEFT JOIN BBOT_GOAL G ON G.GOAL_ID = A.GOAL_ID
WHERE A.ACTION_RGOAL = 'Y'
AND BAS.ASESS_DATE &lt;= #{endDate} AND BAS.ASESS_DATE &gt;= #{startDate}
GROUP BY G.GOAL_ID
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.MessageMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="countMessagesInRange" resultType="int" flushCache="true">
SELECT COUNT(MESSA_ID)
FROM BBOT_MESSAGE
WHERE MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<select id="countMessagesInRangeForHour" resultType="int" flushCache="true">
SELECT COUNT(MESSA_ID)
FROM BBOT_MESSAGE
WHERE MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<!-- @TODO Pendiente agregar la fecha -->
<select id="getSummaryByIntentAndSentence" resultType="SummaryMessageBySentence" flushCache="true">
SELECT
DISTINCT(MESSA_CONT) as sentence,
COUNT(MESSA_ID) AS count,
I.INTEN_IDENT as identifier,
I.INTEN_ID as id
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL
AND M.MESSA_DATE &lt;= #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY M.MESSA_CONT, I.INTEN_ID
ORDER BY ${columnSort} ${directionSort} LIMIT ${itemsForPage} OFFSET ${initLimit}
</select>
<select id="countSummaryByIntentAndSentence" resultType="int" flushCache="true">
select count(*) FROM (SELECT
DISTINCT(MESSA_CONT) as sentence,
COUNT(MESSA_ID) AS count,
I.INTEN_IDENT as identifier,
I.INTEN_ID as id
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL
AND M.MESSA_DATE &lt;= #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY M.MESSA_CONT, I.INTEN_ID
ORDER BY count DESC) as BBOT_SUMMARY
</select>
<select id="getSummaryByIntent" resultType="SummaryMessageByIntent" flushCache="true">
SELECT COUNT(MESSA_ID) AS count,
I.INTEN_IDENT as identifier,
I.INTEN_ID as id
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
GROUP BY I.INTEN_ID
ORDER BY count DESC LIMIT 4
</select>
<select id="getSummaryBySentence" resultType="SummaryMessageBySentence" flushCache="true">
SELECT
COUNT(MESSA_ID) as count,
MESSA_CONT as identifier
FROM BBOT_MESSAGE M
WHERE INTEN_ID IS NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
GROUP BY MESSA_CONT
ORDER BY ${columnSort} ${directionSort} LIMIT ${itemsForPage} OFFSET ${initLimit}
</select>
<select id="countSummaryBySentence" resultType="int" flushCache="true">
SELECT count(*) FROM (SELECT
COUNT(MESSA_ID) as count,
MESSA_CONT as identifier
FROM BBOT_MESSAGE M
WHERE INTEN_ID IS NULL
AND M.MESSA_DATE &lt;= #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY MESSA_CONT
ORDER BY count DESC, identifier DESC) as BBOT_SUMMARY
</select>
<select id="countByIntentAndRange" resultType="int" flushCache="true">
SELECT
COUNT(MESSA_ID)
FROM BBOT_MESSAGE
WHERE INTEN_ID IS NOT NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<select id="countBySentencesAndRange" resultType="int" flushCache="true">
SELECT
COUNT(MESSA_ID)
FROM BBOT_MESSAGE WHERE INTEN_ID IS NULL
AND MESSA_DATE &lt;= #{endDate} AND MESSA_DATE &gt;= #{startDate}
</select>
<select id="avgIntentsByCustomerAndRange" resultType="Double" flushCache="true">
SELECT AVG (COUNT_MESSA) FROM
(
SELECT COUNT(MESSA_ID) as COUNT_MESSA,
S.USER_ID
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_SESSION S ON M.SESSION_ID = S.SESSION_ID
WHERE M.INTEN_ID IS NOT NULL AND M.MESSA_DATE &lt; #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY S.USER_ID
) BBOT_INTENT_CUSTOMER
</select>
<select id="countMessageByIntent" resultType="MessageByIntent" flushCache="true">
SELECT
COUNT(M.MESSA_ID) as count,
I.INTEN_IDENT as identifier
FROM BBOT_MESSAGE M
LEFT JOIN BBOT_INTENT I
ON M.INTEN_ID = I.INTEN_ID
WHERE M.INTEN_ID IS NOT NULL AND M.MESSA_DATE &lt; #{endDate} AND M.MESSA_DATE &gt;= #{startDate}
GROUP BY I.INTEN_IDENT
</select>
<select id="countCustomersBySentence" resultType="int" flushCache="true">
SELECT COUNT(distinct USER_ID)
FROM BBOT_SESSION
WHERE SESSION_ID in (select DISTINCT SESSION_ID from BBOT_MESSAGE bm WHERE MESSA_CONT = #{sentence})
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ResponseMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="countMessagesInRange" resultType="int" flushCache="true">
SELECT COUNT(RESPO_ID)
FROM BBOT_RESPONSE
WHERE RESPO_DATE &lt;= #{endDate} AND RESPO_DATE &gt;= #{startDate}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.SessionMapper">
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastDateInRange" resultType="java.sql.Timestamp" flushCache="true">
select SESSION_LEDAT
FROM BBOT_SESSION bas
WHERE SESSION_LEDAT &lt;= #{endDate}
AND SESSION_LEDAT &gt;= #{startDate}
ORDER BY SESSION_LEDAT DESC LIMIT 1
</select>
<select id="countSessionsInRange" resultType="int" flushCache="true">
select COUNT(SESSION_ID)
FROM BBOT_SESSION bas
WHERE SESSION_DATE &lt;= #{endDate}
AND SESSION_DATE &gt;= #{startDate}
</select>
<select id="avgSessionsByCustomerInRange" resultType="Double" flushCache="true">
select avg(SESSION_CANT) FROM
(
select count(USER_ID) as SESSION_CANT
from BBOT_SESSION bas
WHERE SESSION_DATE &lt;= #{endDate} AND SESSION_DATE &gt;= #{startDate} GROUP BY USER_ID
) BBOT_SESSION_COUNT
</select>
<select id="avgFirstResponseTime" resultType="Double" flushCache="true">
SELECT AVG(RESP_TIME)
FROM (
SELECT ((DATE_PART('day', SESSION_FRDAT - SESSION_DATE) * 24 +
DATE_PART('hour', SESSION_FRDAT - SESSION_DATE)) * 60 +
DATE_PART('minute', SESSION_FRDAT - SESSION_DATE)) * 60 +
DATE_PART('second', SESSION_FRDAT - SESSION_DATE) AS RESP_TIME
from BBOT_SESSION bs WHERE SESSION_FRDAT IS NOT null
AND SESSION_DATE &lt;= #{endDate}
AND SESSION_DATE &gt;= #{startDate}
) RESPONSE_DIF
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ETLMessageMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastCorrelativeBySession" resultType="int" flushCache="true">
SELECT IFNULL( (SELECT
MESSA_CORRE
FROM BBOT_MESSAGE
WHERE SESSION_ID = ${sessionId}
ORDER BY MESSA_CORRE DESC
LIMIT 1) ,0) as correlative
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ETLResponseMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastCorrelativeBySession" resultType="int" flushCache="true">
SELECT IFNULL( (SELECT
RESPO_CORR
FROM BBOT_RESPONSE
WHERE SESSION_ID = ${sessionId}
ORDER BY RESPO_CORR DESC
LIMIT 1) ,0) as correlative
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ETLSessionMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastSessionByUser" resultType="Session" flushCache="true">
SELECT
SESSION_ID as id,
SESSION_DATE as sessionDate,
SESSION_LEDAT as lastEventDate,
SESSION_FRDAT as responseDate,
CHANN_ID as channelId,
USER_ID as userId
FROM BBOT_SESSION
WHERE USER_ID = ${userId}
ORDER BY SESSION_DATE DESC
LIMIT 1
</select>
<update id="updateLastEventDate" flushCache="true">
UPDATE
BBOT_SESSION SET
SESSION_LEDAT = ${lastEventDate}
WHERE SESSION_ID = ${sessionID}
</update>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ETLMessageMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastCorrelativeBySession" resultType="int" flushCache="true">
SELECT coalesce( (SELECT
MESSA_CORRE
FROM BBOT_MESSAGE
WHERE SESSION_ID = ${sessionId}
ORDER BY MESSA_CORRE DESC
LIMIT 1) ,0) as correlative
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ETLResponseMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastCorrelativeBySession" resultType="int" flushCache="true">
SELECT coalesce( (SELECT
RESPO_CORR
FROM BBOT_RESPONSE
WHERE SESSION_ID = ${sessionId}
ORDER BY RESPO_CORR DESC
LIMIT 1) ,0) as correlative
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.bytebot.dao.jdbc.ETLSessionMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getLastSessionByUser" resultType="Session" flushCache="true">
SELECT
SESSION_ID as id,
SESSION_DATE as sessionDate,
SESSION_LEDAT as lastEventDate,
SESSION_FRDAT as responseDate,
CHANN_ID as channelId,
USER_ID as userId
FROM BBOT_SESSION
WHERE USER_ID = ${userId}
ORDER BY SESSION_DATE DESC
LIMIT 1
</select>
<update id="updateLastEventDate" flushCache="true">
UPDATE
BBOT_SESSION SET
SESSION_LEDAT = ${lastEventDate}
WHERE SESSION_ID = ${sessionID}
</update>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bytesw.xdf.dao.jdbc.AuditMapper" >
<!-- In Config XML file -->
<cache readOnly="true"></cache>
<select id="getAuditData" resultType="hashmap" flushCache="true">
SELECT ${columns},
SECURITY_AUDIT.REV_USER as username,
SECURITY_AUDIT.REV_MODIF as date,
${tableName}.REVTYPE as revisionType
FROM ${tableName}
LEFT JOIN SECURITY_AUDIT
ON ${tableName}.REV = SECURITY_AUDIT.REV_ID
WHERE ${pkName} = #{pkValue} ORDER BY SECURITY_AUDIT.REV_MODIF DESC
LIMIT ${page},${pageSize}
</select>
<select id="countAuditData" resultType="int" flushCache="true">
SELECT count(${pkName})
FROM ${tableName}
WHERE ${pkName} = #{pkValue}
</select>
</mapper>
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -6,10 +6,23 @@ ...@@ -6,10 +6,23 @@
<configuration> <configuration>
<properties resource="mybatis.properties" /> <properties resource="mybatis.properties" />
<typeAliases> <typeAliases>
<typeAlias type="com.bytesw.bytebot.bean.SummaryMessageByIntentBean" alias="SummaryMessageByIntent"/>
<typeAlias type="com.bytesw.bytebot.bean.SummaryMessageBySentenceBean" alias="SummaryMessageBySentence"/>
<typeAlias type="com.bytesw.bytebot.bean.ActionSummaryByGoalBean" alias="ActionSummaryByGoal"/>
<typeAlias type="com.bytesw.bytebot.bean.MessageByIntentBean" alias="MessageByIntent"/>
<typeAlias type="com.bytesw.bytebot.etl.beans.SessionBean" alias="Session"/>
</typeAliases> </typeAliases>
<mappers> <mappers>
<mapper resource="config/mappers/xdf/${database-type-xdf}/AuditMapper.xml"/> <mapper resource="config/mappers/xdf/${database-type-xdf}/AuditMapper.xml"/>
<mapper resource="config/mappers/bytebot/${database-type-xdf}/SessionMapper.xml"/>
<mapper resource="config/mappers/bytebot/${database-type-xdf}/MessageMapper.xml"/>
<mapper resource="config/mappers/bytebot/${database-type-xdf}/ResponseMapper.xml"/>
<mapper resource="config/mappers/bytebot/${database-type-xdf}/ActionMapper.xml"/>
<mapper resource="config/mappers/xdf/${database-type-xdf}/AuditMapper.xml"/>
<mapper resource="config/mappers/etl/${database-type-xdf}/SessionMapper.xml"/>
<mapper resource="config/mappers/etl/${database-type-xdf}/MessageMapper.xml"/>
<mapper resource="config/mappers/etl/${database-type-xdf}/ResponseMapper.xml"/>
</mappers> </mappers>
</configuration> </configuration>
database-type-xdf=mysql database-type-xdf=postgres
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