diff --git a/src/main/java/org/sadtech/autoresponder/Autoresponder.java b/src/main/java/org/sadtech/autoresponder/AutoResponder.java similarity index 79% rename from src/main/java/org/sadtech/autoresponder/Autoresponder.java rename to src/main/java/org/sadtech/autoresponder/AutoResponder.java index d23ace1..a093ba7 100644 --- a/src/main/java/org/sadtech/autoresponder/Autoresponder.java +++ b/src/main/java/org/sadtech/autoresponder/AutoResponder.java @@ -15,8 +15,6 @@ import org.sadtech.autoresponder.util.Parser; import java.util.HashSet; import java.util.Optional; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Реализуют основную логику автоответчика. @@ -24,7 +22,7 @@ import java.util.regex.Pattern; * @author upagge [07/07/2019] */ @Slf4j -public class Autoresponder { +public class AutoResponder { @Description("Компоратор для сортировки Unit-ов") private static final UnitPriorityComparator UNIT_PRIORITY_COMPARATOR = new UnitPriorityComparator(); @@ -40,7 +38,7 @@ public class Autoresponder { @Getter private final UnitPointerService unitPointerService; - public Autoresponder(UnitPointerService unitPointerService, Set startUnits) { + public AutoResponder(UnitPointerService unitPointerService, Set startUnits) { this.startUnits = startUnits; this.unitPointerService = unitPointerService; } @@ -56,7 +54,7 @@ public class Autoresponder { UnitPointer unitPointer = checkAndAddPerson(personId); Unit unit; try { - if (unitPointer.getUnit() == null || unitPointer.getUnit().getNextUnits() == null) { + if (unitPointer.getUnit() == null || unitPointer.getUnit().getNextUnits() == null || unitPointer.getUnit().getNextUnits().isEmpty()) { unit = nextUnit(startUnits, message); } else { unit = nextUnit(unitPointer.getUnit().getNextUnits(), message); @@ -75,23 +73,22 @@ public class Autoresponder { * @param message Запрос пользователя - текстовое сообщение * @return Юнит, который нуждается в обработке в соответствии с запросом пользователя */ - private Unit nextUnit(Set nextUnits, String message) { - Optional unit = nextUnits.stream() + private Unit nextUnit(@NonNull Set nextUnits, String message) { + Set searchUnit = new HashSet<>(); + + nextUnits.stream() .filter(nextUnit -> nextUnit.getPattern() != null && patternReg(nextUnit, message)) - .max(UNIT_PRIORITY_COMPARATOR); + .forEach(searchUnit::add); - if (!unit.isPresent()) { - unit = nextUnits.stream() - .filter(nextUnit -> percentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold()) - .max(UNIT_PRIORITY_COMPARATOR); - } + nextUnits.stream() + .filter(nextUnit -> percentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold()) + .forEach(searchUnit::add); - if (!unit.isPresent()) { - unit = nextUnits.stream() - .filter(nextUnit -> (nextUnit.getPattern() == null && nextUnit.getKeyWords() == null)) - .max(UNIT_PRIORITY_COMPARATOR); - } - return unit.orElseThrow(NotFoundUnitException::new); + nextUnits.stream() + .filter(nextUnit -> (nextUnit.getPattern() == null && (nextUnit.getKeyWords() == null || nextUnit.getKeyWords().isEmpty()))) + .forEach(searchUnit::add); + + return searchUnit.stream().max(UNIT_PRIORITY_COMPARATOR).orElseThrow(NotFoundUnitException::new); } /** @@ -100,7 +97,7 @@ public class Autoresponder { * @param personId Идентификатор пользователя * @return {@link UnitPointer}, который сохраняет {@link Unit}, который был обработан последним */ - private UnitPointer checkAndAddPerson(Integer personId) { + private UnitPointer checkAndAddPerson(@NonNull Integer personId) { UnitPointer unitPointer; if (unitPointerService.check(personId)) { unitPointer = unitPointerService.getByEntityId(personId); @@ -112,14 +109,12 @@ public class Autoresponder { } - private boolean patternReg(Unit unit, String message) { - Pattern pattern = unit.getPattern(); - Matcher m = pattern.matcher(message); - return m.find(); + private boolean patternReg(@NonNull Unit unit, String message) { + return message.matches(unit.getPattern().pattern()); } private Double percentageMatch(Unit unit, Set words) { - if (unit.getKeyWords() != null) { + if (unit.getKeyWords() != null && !unit.getKeyWords().isEmpty()) { Set temp = new HashSet<>(unit.getKeyWords()); temp.retainAll(words); log.info("Ключевые слова юнита: {} ({})", unit.getKeyWords(), unit.getKeyWords().size()); diff --git a/src/main/java/org/sadtech/autoresponder/entity/Unit.java b/src/main/java/org/sadtech/autoresponder/entity/Unit.java index a27d3f7..3f43dfc 100644 --- a/src/main/java/org/sadtech/autoresponder/entity/Unit.java +++ b/src/main/java/org/sadtech/autoresponder/entity/Unit.java @@ -3,10 +3,10 @@ package org.sadtech.autoresponder.entity; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.ToString; import org.sadtech.autoresponder.util.Description; -import java.util.Arrays; -import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; @@ -17,52 +17,30 @@ import java.util.regex.Pattern; */ @Getter @EqualsAndHashCode +@ToString +@Setter public abstract class Unit { @Description("Ключевые слова") - private Set keyWords; + protected Set keyWords; - @Setter @Description("Регулярное выражение") - private Pattern pattern; + protected Pattern pattern; - @Setter - // todo [upagge] [07/07/2019]: Придумать нормальное описание - private Integer matchThreshold = 10; + @Description("Значение минимального отношения количества найденых ключевых слов, к количеству ключевых слов Unit-а") + protected Integer matchThreshold; - @Setter @Description("Значение приоритета") - private Integer priority = 10; + protected Integer priority; @Description("Множество следующих Unit в сценарии") - private Set nextUnits; + protected Set nextUnits; - public void setKeyWord(String... keyWord) { - if (this.keyWords == null) { - this.keyWords = new HashSet<>(); - } - this.keyWords.addAll(Arrays.asList(keyWord)); + protected Unit(Set keyWords, Pattern pattern, Integer matchThreshold, Integer priority, Set nextUnits) { + this.keyWords = keyWords; + this.pattern = pattern; + this.matchThreshold = Optional.ofNullable(matchThreshold).orElse(10); + this.priority = Optional.ofNullable(priority).orElse(10); + this.nextUnits = nextUnits; } - - public void setKeyWords(Set keyWords) { - if (this.keyWords == null) { - this.keyWords = new HashSet<>(); - } - this.keyWords.addAll(keyWords); - } - - public void setNextUnit(Unit... unit) { - if (nextUnits == null) { - nextUnits = new HashSet<>(); - } - nextUnits.addAll(Arrays.asList(unit)); - } - - public void setNextUnits(Set nextUnits) { - if (nextUnits == null) { - nextUnits = new HashSet<>(); - } - this.nextUnits.addAll(nextUnits); - } - } diff --git a/src/main/java/org/sadtech/autoresponder/exception/NotFoundUnitException.java b/src/main/java/org/sadtech/autoresponder/exception/NotFoundUnitException.java index 708ec1b..bbab6f6 100644 --- a/src/main/java/org/sadtech/autoresponder/exception/NotFoundUnitException.java +++ b/src/main/java/org/sadtech/autoresponder/exception/NotFoundUnitException.java @@ -6,4 +6,5 @@ package org.sadtech.autoresponder.exception; * @author upagge [07/07/2019] */ public class NotFoundUnitException extends RuntimeException { + } diff --git a/src/main/java/org/sadtech/autoresponder/repository/UnitPointerRepositoryMap.java b/src/main/java/org/sadtech/autoresponder/repository/UnitPointerRepositoryMap.java index 4f606b2..8b4e1a0 100644 --- a/src/main/java/org/sadtech/autoresponder/repository/UnitPointerRepositoryMap.java +++ b/src/main/java/org/sadtech/autoresponder/repository/UnitPointerRepositoryMap.java @@ -1,5 +1,6 @@ package org.sadtech.autoresponder.repository; +import lombok.NonNull; import org.sadtech.autoresponder.entity.UnitPointer; import java.util.Collection; @@ -16,27 +17,27 @@ public class UnitPointerRepositoryMap implements UnitPointerRepository { private Map unitPointerMap = new HashMap<>(); @Override - public void add(UnitPointer unitPointer) { + public void add(@NonNull UnitPointer unitPointer) { unitPointerMap.put(unitPointer.getEntityId(), unitPointer); } @Override - public void edit(UnitPointer unitPointer) { + public void edit(@NonNull UnitPointer unitPointer) { unitPointerMap.get(unitPointer.getEntityId()).setUnit(unitPointer.getUnit()); } @Override - public void remove(Integer entityId) { + public void remove(@NonNull Integer entityId) { unitPointerMap.remove(entityId); } @Override - public void addAll(Collection unitPointers) { + public void addAll(@NonNull Collection unitPointers) { unitPointers.parallelStream().forEach(unitPointer -> unitPointerMap.put(unitPointer.getEntityId(), unitPointer)); } @Override - public UnitPointer findByEntityId(Integer entityId) { + public UnitPointer findByEntityId(@NonNull Integer entityId) { return unitPointerMap.get(entityId); } } diff --git a/src/main/java/org/sadtech/autoresponder/service/UnitPointerServiceImpl.java b/src/main/java/org/sadtech/autoresponder/service/UnitPointerServiceImpl.java index 94d7693..27cd202 100644 --- a/src/main/java/org/sadtech/autoresponder/service/UnitPointerServiceImpl.java +++ b/src/main/java/org/sadtech/autoresponder/service/UnitPointerServiceImpl.java @@ -1,44 +1,40 @@ package org.sadtech.autoresponder.service; +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.sadtech.autoresponder.entity.Unit; import org.sadtech.autoresponder.entity.UnitPointer; import org.sadtech.autoresponder.repository.UnitPointerRepository; -import org.sadtech.autoresponder.repository.UnitPointerRepositoryMap; @Slf4j public class UnitPointerServiceImpl implements UnitPointerService { - private UnitPointerRepository unitPointerRepository; - - public UnitPointerServiceImpl() { - this.unitPointerRepository = new UnitPointerRepositoryMap(); - } + private final UnitPointerRepository unitPointerRepository; public UnitPointerServiceImpl(UnitPointerRepository unitPointerRepository) { this.unitPointerRepository = unitPointerRepository; } @Override - public UnitPointer getByEntityId(Integer entityId) { + public UnitPointer getByEntityId(@NonNull Integer entityId) { return unitPointerRepository.findByEntityId(entityId); } @Override - public void edit(Integer personId, Unit unit) { + public void edit(@NonNull Integer personId, Unit unit) { if (check(personId)) { unitPointerRepository.edit(new UnitPointer(personId, unit)); } } @Override - public void add(UnitPointer unitPointer) { + public void add(@NonNull UnitPointer unitPointer) { unitPointerRepository.add(unitPointer); log.info("Пользователь отправлен в репозиторий"); } @Override - public boolean check(Integer entityId) { + public boolean check(@NonNull Integer entityId) { return unitPointerRepository.findByEntityId(entityId) != null; } } diff --git a/src/test/java/org/sadtech/autoresponder/AutoresponderTest.java b/src/test/java/org/sadtech/autoresponder/AutoResponderTest.java similarity index 71% rename from src/test/java/org/sadtech/autoresponder/AutoresponderTest.java rename to src/test/java/org/sadtech/autoresponder/AutoResponderTest.java index d0f7b11..b6ccd13 100644 --- a/src/test/java/org/sadtech/autoresponder/AutoresponderTest.java +++ b/src/test/java/org/sadtech/autoresponder/AutoResponderTest.java @@ -12,42 +12,53 @@ import org.sadtech.autoresponder.test.TestUnit; import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class AutoresponderTest { +public class AutoResponderTest { - private Autoresponder autoresponder; + private AutoResponder autoresponder; @Before public void setUp() { - TestUnit dela = new TestUnit(); - dela.setKeyWord("дела", "делишки"); - dela.setMessage("хорошо"); + TestUnit dela = TestUnit.builder() + .keyWord("дела") + .keyWord("делишки") + .message("хорошо") + .build(); - TestUnit delaTop = new TestUnit(); - delaTop.setPriority(100); - delaTop.setKeyWord("делишки"); - delaTop.setMessage("отлично"); + TestUnit delaTop = TestUnit.builder() + .priority(100) + .keyWord("делишки") + .message("отлично") + .build(); - TestUnit hello = new TestUnit(); - hello.setMessage("тест"); - hello.setKeyWord("привет"); - hello.setNextUnit(dela); - hello.setNextUnit(delaTop); + TestUnit hello = TestUnit.builder() + .keyWord("привет") + .message("тест") + .nextUnit(dela) + .nextUnit(delaTop) + .build(); - TestUnit number = new TestUnit(); - number.setKeyWord("89101234567"); - number.setMessage("ответ"); - TestUnit regExp = new TestUnit(); - regExp.setPattern(Pattern.compile("^((8|\\+7)[\\- ]?)?(\\(?\\d{3}\\)?[\\- ]?)?[\\d\\- ]{7,10}$")); - regExp.setMessage("регулярка"); - dela.setNextUnit(regExp); - dela.setNextUnit(number); + TestUnit number = TestUnit.builder() + .keyWord("89101234567") + .message("ответ") + .build(); - TestUnit unreal = new TestUnit(); - unreal.setKeyWord("витамин", "мультифрукт", "арбуз", "параметр"); - unreal.setMessage("победа"); - unreal.setMatchThreshold(100); + TestUnit regExp = TestUnit.builder() + .pattern(Pattern.compile("^((8|\\+7)[\\- ]?)?(\\(?\\d{3}\\)?[\\- ]?)?[\\d\\- ]{7,10}$")) + .message("регулярка") + .build(); + dela.setNextUnits(Stream.of(regExp, number).collect(Collectors.toSet())); + + Set strings = Stream.of("витамин", "мультифрукт", "арбуз", "параметр").collect(Collectors.toSet()); + + TestUnit unreal = TestUnit.builder() + .keyWords(strings) + .message("победа") + .matchThreshold(100) + .build(); Set testUnits = new HashSet<>(); testUnits.add(hello); @@ -55,7 +66,7 @@ public class AutoresponderTest { testUnits.add(unreal); UnitPointerServiceImpl unitPointerService = new UnitPointerServiceImpl(new UnitPointerRepositoryMap()); - autoresponder = new Autoresponder(unitPointerService, testUnits); + autoresponder = new AutoResponder(unitPointerService, testUnits); } @Test @@ -68,8 +79,7 @@ public class AutoresponderTest { @Test public void defaultAnswer() { - TestUnit defaultUnit = new TestUnit(); - defaultUnit.setMessage("не знаю"); + TestUnit defaultUnit = TestUnit.builder().message("не знаю").build(); autoresponder.setDefaultUnit(defaultUnit); Assert.assertEquals(((TestUnit) autoresponder.answer(2, "пока")).getMessage(), "не знаю"); @@ -113,8 +123,7 @@ public class AutoresponderTest { @Test public void generalAnswer() { - TestUnit defaultUnit = new TestUnit(); - defaultUnit.setMessage("не знаю"); + TestUnit defaultUnit = TestUnit.builder().message("не знаю").build(); autoresponder.setDefaultUnit(defaultUnit); String answer = ((TestUnit) autoresponder.answer(1, "привет это тестирование функциональности")).getMessage(); Assert.assertEquals("тест", answer); diff --git a/src/test/java/org/sadtech/autoresponder/test/TestUnit.java b/src/test/java/org/sadtech/autoresponder/test/TestUnit.java index 40c3cce..6922a72 100644 --- a/src/test/java/org/sadtech/autoresponder/test/TestUnit.java +++ b/src/test/java/org/sadtech/autoresponder/test/TestUnit.java @@ -1,32 +1,30 @@ package org.sadtech.autoresponder.test; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Singular; +import lombok.ToString; import org.sadtech.autoresponder.entity.Unit; -import java.util.Objects; +import java.util.Set; +import java.util.regex.Pattern; +@Getter +@EqualsAndHashCode(callSuper = true) +@ToString public class TestUnit extends Unit { private String message; - public String getMessage() { - return message; - } - - public void setMessage(String message) { + @Builder + public TestUnit(@Singular(value = "keyWord") Set keyWords, + Pattern pattern, + Integer matchThreshold, + Integer priority, + @Singular(value = "nextUnit") Set nextUnits, + String message) { + super(keyWords, pattern, matchThreshold, priority, nextUnits); this.message = message; } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TestUnit)) return false; - if (!super.equals(o)) return false; - TestUnit testUnit = (TestUnit) o; - return Objects.equals(message, testUnit.message); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), message); - } }