Merge branch 'release/release-1.6.0'

This commit is contained in:
Mark Struchkov 2019-05-18 13:09:20 +03:00
commit 2c2547013b
10 changed files with 134 additions and 94 deletions

10
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>org.sadtech.autoresponder</groupId> <groupId>org.sadtech.autoresponder</groupId>
<artifactId>autoresponder</artifactId> <artifactId>autoresponder</artifactId>
<version>1.5.0-RELEASE</version> <version>1.6.0-RELEASE</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<build> <build>
<plugins> <plugins>
@ -23,14 +23,14 @@
</build> </build>
<properties> <properties>
<log4j>1.2.17</log4j> <slf4j.ver>1.7.26</slf4j.ver>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>log4j</artifactId> <artifactId>slf4j-api</artifactId>
<version>${log4j}</version> <version>${slf4j.ver}</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,11 +1,13 @@
package org.sadtech.autoresponder; package org.sadtech.autoresponder;
import org.apache.log4j.Logger;
import org.sadtech.autoresponder.compare.UnitPriorityComparator; import org.sadtech.autoresponder.compare.UnitPriorityComparator;
import org.sadtech.autoresponder.entity.UnitPointer;
import org.sadtech.autoresponder.entity.Unit; import org.sadtech.autoresponder.entity.Unit;
import org.sadtech.autoresponder.entity.UnitPointer;
import org.sadtech.autoresponder.exception.NotFoundUnitException;
import org.sadtech.autoresponder.service.UnitPointerService; import org.sadtech.autoresponder.service.UnitPointerService;
import org.sadtech.autoresponder.util.Parser; import org.sadtech.autoresponder.util.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional; import java.util.Optional;
@ -13,79 +15,76 @@ import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/*
Отвечает за функционирование автоответчика
*/
public class Autoresponder { public class Autoresponder {
private static final Logger log = Logger.getLogger(Autoresponder.class); private static final Logger log = LoggerFactory.getLogger(Autoresponder.class);
private static final UnitPriorityComparator UNIT_PRIORITY_COMPARATOR = new UnitPriorityComparator();
private Set<Unit> menuUnits; private final Set<Unit> startUnits;
private UnitPointerService unitPointerService; private Unit defaultUnit;
private final UnitPointerService unitPointerService;
public Autoresponder(UnitPointerService unitPointerService) { public Autoresponder(UnitPointerService unitPointerService, Set<Unit> startUnits) {
this.startUnits = startUnits;
this.unitPointerService = unitPointerService; this.unitPointerService = unitPointerService;
} }
public void setMenuUnits(Set<Unit> menuUnits) {
this.menuUnits = menuUnits;
}
public UnitPointerService getUnitPointerService() { public UnitPointerService getUnitPointerService() {
return unitPointerService; return unitPointerService;
} }
public void setUnitPointerService(UnitPointerService unitPointerService) { public void setDefaultUnit(Unit defaultUnit) {
this.unitPointerService = unitPointerService; this.defaultUnit = defaultUnit;
} }
public Unit answer(Integer idPerson, String message) { public Unit answer(Integer personId, String message) {
UnitPointer unitPointer = checkAndAddPerson(idPerson); UnitPointer unitPointer = checkAndAddPerson(personId);
Unit unit; Unit unit;
if (unitPointer.getUnit() == null) { try {
unit = nextUnit(menuUnits, message); if (unitPointer.getUnit() == null || unitPointer.getUnit().getNextUnits() == null) {
} else { unit = nextUnit(startUnits, message); // выбирает unit из startUnits, если пользователь обращается впервые
if (unitPointer.getUnit().getNextUnits() == null) {
unit = nextUnit(menuUnits, message);
} else { } else {
unit = nextUnit(unitPointer.getUnit().getNextUnits(), message); unit = nextUnit(unitPointer.getUnit().getNextUnits(), message);
} }
unitPointerService.edit(personId, unit);
} catch (NotFoundUnitException e) {
unit = defaultUnit;
} }
if (unit != null) { return Optional.ofNullable(unit).orElseThrow(NotFoundUnitException::new);
unitPointer.setUnit(unit);
}
return unit;
}
private UnitPointer checkAndAddPerson(Integer idPerson) {
UnitPointer unitPointer;
if (unitPointerService.check(idPerson)) {
unitPointer = unitPointerService.getByEntityId(idPerson);
} else {
unitPointer = new UnitPointer(idPerson);
unitPointerService.add(unitPointer);
}
return unitPointer;
} }
private Unit nextUnit(Set<Unit> nextUnits, String message) { private Unit nextUnit(Set<Unit> nextUnits, String message) {
if (nextUnits.size() > 0) { Optional<Unit> unit = nextUnits.stream()
UnitPriorityComparator unitPriorityComparator = new UnitPriorityComparator(); .filter(nextUnit -> nextUnit.getPattern() != null)
Optional<Unit> patternUnits = nextUnits.stream().filter(nextUnit -> nextUnit.getPattern() != null).filter(nextUnit -> patternReg(nextUnit, message)).max(unitPriorityComparator); .filter(nextUnit -> patternReg(nextUnit, message))
.max(UNIT_PRIORITY_COMPARATOR);
if (!patternUnits.isPresent()) { if (!unit.isPresent()) {
patternUnits = nextUnits.stream() unit = nextUnits.stream()
.filter(nextUnit -> textPercentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold()) .filter(nextUnit -> textPercentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold())
.max(unitPriorityComparator); .max(UNIT_PRIORITY_COMPARATOR);
}
if (!patternUnits.isPresent()) {
patternUnits = nextUnits.stream()
.filter(nextUnit -> (nextUnit.getPattern() == null && nextUnit.getKeyWords() == null))
.max(unitPriorityComparator);
}
return patternUnits.orElse(null);
} else {
return null;
} }
if (!unit.isPresent()) {
unit = nextUnits.stream()
.filter(nextUnit -> (nextUnit.getPattern() == null && nextUnit.getKeyWords() == null))
.max(UNIT_PRIORITY_COMPARATOR);
}
return unit.orElseThrow(NotFoundUnitException::new);
}
private UnitPointer checkAndAddPerson(Integer personId) {
UnitPointer unitPointer;
if (unitPointerService.check(personId)) {
unitPointer = unitPointerService.getByEntityId(personId);
} else {
unitPointer = new UnitPointer(personId);
unitPointerService.add(unitPointer);
}
return unitPointer;
} }
private boolean patternReg(Unit unit, String message) { private boolean patternReg(Unit unit, String message) {
@ -98,7 +97,6 @@ public class Autoresponder {
if (unit.getKeyWords() != null) { if (unit.getKeyWords() != null) {
Set<String> temp = new HashSet<>(unit.getKeyWords()); Set<String> temp = new HashSet<>(unit.getKeyWords());
temp.retainAll(words); temp.retainAll(words);
log.info("Юнит: " + unit.getClass().getSimpleName());
log.info("Ключевые слова юнита: " + unit.getKeyWords() + " (" + unit.getKeyWords().size() + ")"); log.info("Ключевые слова юнита: " + unit.getKeyWords() + " (" + unit.getKeyWords().size() + ")");
log.info("Ключевые слова от пользователя: " + words); log.info("Ключевые слова от пользователя: " + words);
log.info("Пересечение: " + temp + " (" + temp.size() + ")"); log.info("Пересечение: " + temp + " (" + temp.size() + ")");

View File

@ -1,51 +1,56 @@
package org.sadtech.autoresponder.entity; package org.sadtech.autoresponder.entity;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/*
Абстрактный класс, предпологающий какие-то действия
*/
public abstract class Unit { public abstract class Unit {
private Set<String> keyWords; private Set<String> keyWords;
private Pattern pattern; private Pattern pattern;
private Integer matchThreshold; private Integer matchThreshold = 10;
private Integer priority; private Integer priority = 10;
private Set<Unit> nextUnits; private Set<Unit> nextUnits;
public Unit() { public void setKeyWord(String... keyWord) {
priority = 10; if (this.keyWords == null) {
matchThreshold = 10; this.keyWords = new HashSet<>();
}
public Unit(Set<String> keyWords, Pattern pattern, Integer matchThreshold, Integer priority, Set<Unit> nextUnits) {
this.keyWords = keyWords;
this.pattern = pattern;
this.matchThreshold = matchThreshold;
this.priority = priority;
this.nextUnits = nextUnits;
}
public void setKeyWord(String keyWord) {
if (keyWords == null) {
keyWords = new HashSet<>();
} }
keyWords.add(keyWord); this.keyWords.addAll(Arrays.asList(keyWord));
} }
public void setNextUnit(Unit unit) { public void setKeyWords(Set<String> keyWords) {
if (nextUnits == null) { if (this.keyWords == null) {
nextUnits = new HashSet<>(); this.keyWords = new HashSet<>();
} }
nextUnits.add(unit); this.keyWords.addAll(keyWords);
} }
public Set<String> getKeyWords() { public Set<String> getKeyWords() {
return keyWords; return keyWords;
} }
public void setKeyWords(Set<String> keyWords) { public void setNextUnit(Unit... unit) {
this.keyWords = keyWords; if (nextUnits == null) {
nextUnits = new HashSet<>();
}
nextUnits.addAll(Arrays.asList(unit));
}
public void setNextUnits(Set<Unit> nextUnits) {
if (nextUnits == null) {
nextUnits = new HashSet<>();
}
this.nextUnits.addAll(nextUnits);
}
public Set<Unit> getNextUnits() {
return nextUnits;
} }
public Integer getMatchThreshold() { public Integer getMatchThreshold() {
@ -64,14 +69,6 @@ public abstract class Unit {
this.priority = priority; this.priority = priority;
} }
public Set<Unit> getNextUnits() {
return nextUnits;
}
public void setNextUnits(Set<Unit> nextUnits) {
this.nextUnits = nextUnits;
}
public Pattern getPattern() { public Pattern getPattern() {
return pattern; return pattern;
} }
@ -83,7 +80,7 @@ public abstract class Unit {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (!(o instanceof Unit)) return false;
Unit unit = (Unit) o; Unit unit = (Unit) o;
return Objects.equals(keyWords, unit.keyWords) && return Objects.equals(keyWords, unit.keyWords) &&
Objects.equals(pattern, unit.pattern) && Objects.equals(pattern, unit.pattern) &&

View File

@ -2,6 +2,9 @@ package org.sadtech.autoresponder.entity;
import java.util.Objects; import java.util.Objects;
/*
Сохраняет юнит, на котором остановился пользователь.
*/
public class UnitPointer { public class UnitPointer {
private Integer entityId; private Integer entityId;
@ -45,4 +48,12 @@ public class UnitPointer {
public int hashCode() { public int hashCode() {
return Objects.hash(entityId, unit); return Objects.hash(entityId, unit);
} }
@Override
public String toString() {
return "UnitPointer{" +
"entityId=" + entityId +
", unit=" + unit +
'}';
}
} }

View File

@ -0,0 +1,4 @@
package org.sadtech.autoresponder.exception;
public class NotFoundUnitException extends RuntimeException {
}

View File

@ -8,6 +8,8 @@ public interface UnitPointerRepository {
Integer add(UnitPointer unitPointer); Integer add(UnitPointer unitPointer);
void edit(UnitPointer unitPointer);
void remove(Integer entityId); void remove(Integer entityId);
void addAll(Map<Integer, UnitPointer> unitPointerMap); void addAll(Map<Integer, UnitPointer> unitPointerMap);

View File

@ -15,6 +15,11 @@ public class UnitPointerRepositoryMap implements UnitPointerRepository {
return unitPointer.getEntityId(); return unitPointer.getEntityId();
} }
@Override
public void edit(UnitPointer unitPointer) {
unitPointerMap.get(unitPointer.getEntityId()).setUnit(unitPointer.getUnit());
}
@Override @Override
public void remove(Integer entityId) { public void remove(Integer entityId) {
unitPointerMap.remove(entityId); unitPointerMap.remove(entityId);

View File

@ -1,5 +1,6 @@
package org.sadtech.autoresponder.service; package org.sadtech.autoresponder.service;
import org.sadtech.autoresponder.entity.Unit;
import org.sadtech.autoresponder.entity.UnitPointer; import org.sadtech.autoresponder.entity.UnitPointer;
public interface UnitPointerService { public interface UnitPointerService {
@ -10,4 +11,6 @@ public interface UnitPointerService {
UnitPointer getByEntityId(Integer entityId); UnitPointer getByEntityId(Integer entityId);
void edit(Integer personId, Unit unit);
} }

View File

@ -1,13 +1,15 @@
package org.sadtech.autoresponder.service; package org.sadtech.autoresponder.service;
import org.apache.log4j.Logger; import org.sadtech.autoresponder.entity.Unit;
import org.sadtech.autoresponder.entity.UnitPointer; import org.sadtech.autoresponder.entity.UnitPointer;
import org.sadtech.autoresponder.repository.UnitPointerRepository; import org.sadtech.autoresponder.repository.UnitPointerRepository;
import org.sadtech.autoresponder.repository.UnitPointerRepositoryMap; import org.sadtech.autoresponder.repository.UnitPointerRepositoryMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UnitPointerServiceImpl implements UnitPointerService { public class UnitPointerServiceImpl implements UnitPointerService {
private static final Logger log = Logger.getLogger(UnitPointerServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(UnitPointerServiceImpl.class);
private UnitPointerRepository unitPointerRepository; private UnitPointerRepository unitPointerRepository;
@ -24,6 +26,13 @@ public class UnitPointerServiceImpl implements UnitPointerService {
return unitPointerRepository.findByEntityId(entityId); return unitPointerRepository.findByEntityId(entityId);
} }
@Override
public void edit(Integer personId, Unit unit) {
if (check(personId)) {
unitPointerRepository.edit(new UnitPointer(personId, unit));
}
}
@Override @Override
public void add(UnitPointer unitPointer) { public void add(UnitPointer unitPointer) {
unitPointerRepository.add(unitPointer); unitPointerRepository.add(unitPointer);

View File

@ -4,9 +4,19 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
Возвращает Set слов из текста
*/
public class Parser { public class Parser {
private static final Set<String> pretexts = Stream
.of("в", "без", "до", "из", "к", "на", "по", "о", "от", "перед", "при", "с", "у", "за", "над", "об",
"под", "про", "для")
.collect(Collectors.toSet());
private Parser() { private Parser() {
throw new IllegalStateException("Utility Class"); throw new IllegalStateException("Utility Class");
} }
@ -18,6 +28,7 @@ public class Parser {
while (m.find()) { while (m.find()) {
words.add(m.group().toLowerCase()); words.add(m.group().toLowerCase());
} }
words.removeAll(pretexts);
return words; return words;
} }