all sorts of things
continuous-integration/drone/push Build is passing Details

This commit is contained in:
qvalentin 2022-05-16 21:09:45 +02:00
parent d1fdad7cf9
commit 3ef31c9c3c
Signed by: qvalentin
GPG Key ID: C979FA1EAFCABF1C
23 changed files with 228 additions and 27 deletions

View File

@ -28,7 +28,7 @@ abstract public class Subcommand {
private void commandExits(String command) { private void commandExits(String command) {
if (commands.get(command) == null) { if (commands.get(command) == null) {
throw new CliError("Subcommand does not exist! " + getUsage()); throw new CliError("Subcommand " + command + " does not exist! " + getUsage());
} }
} }
} }

View File

@ -12,6 +12,7 @@ public class LinkCommands extends Subcommand {
public LinkCommands(LinkCliAdapter linkCliAdapter) { public LinkCommands(LinkCliAdapter linkCliAdapter) {
this.linkCliAdapter = linkCliAdapter; this.linkCliAdapter = linkCliAdapter;
commands.put("add", this::addLink); commands.put("add", this::addLink);
commands.put("get", this::getAll);
} }
@Override @Override
@ -26,10 +27,13 @@ public class LinkCommands extends Subcommand {
} }
private String addLink(String[] args) { private String addLink(String[] args) {
linkCliAdapter.addLink(args[1], linkCliAdapter.addLink(args[1],
Arrays.stream(Arrays.copyOfRange(args, 3, args.length)).collect(Collectors.toSet()), Arrays.stream(Arrays.copyOfRange(args, 3, args.length)).collect(Collectors.toSet()),
args[2]); args[2]);
return "Added the new Link"; return "Added the new Link";
} }
private String getAll(String[] args) {
return String.join(System.lineSeparator(), linkCliAdapter.getLinks());
}
} }

View File

@ -9,7 +9,6 @@ public class TagCommands extends Subcommand {
final private CustomTagsCliAdapter customTagsCliAdapter; final private CustomTagsCliAdapter customTagsCliAdapter;
final private HashMap<String, Function<String[], String>> commands = new HashMap<>();
public TagCommands(CustomTagsCliAdapter customTagsCliAdapter) { public TagCommands(CustomTagsCliAdapter customTagsCliAdapter) {
this.customTagsCliAdapter = customTagsCliAdapter; this.customTagsCliAdapter = customTagsCliAdapter;
@ -24,7 +23,7 @@ public class TagCommands extends Subcommand {
@Override @Override
public String getUsage() { public String getUsage() {
return "Usage: " + System.lineSeparator()+ return "Usage: " + System.lineSeparator()+
getSubcommand() + "add tagName tagRegexExpression"; getSubcommand() + " add tagName tagRegexExpression";
} }
private String addCustomTag(String[] args) { private String addCustomTag(String[] args) {

View File

@ -0,0 +1,96 @@
package main;
import category.CategoryRepository;
import category.CategoryUseCase;
import category.RandomCategoryIdGenerator;
import cli.CliError;
import cli.Subcommand;
import cli.category.CategoryCliAdapter;
import cli.category.CategoryCommands;
import cli.link.LinkCliAdapter;
import cli.link.LinkCommands;
import cli.tag.CustomTagsCliAdapter;
import cli.tag.TagCommands;
import link.LinkRepository;
import link.LinkUseCase;
import link.RandomLinkIdGenerator;
import persistence.GenericCSVDAO;
import persistence.category.CSVCategoryPersistenceAdapter;
import persistence.category.CategoryEntity;
import persistence.customTags.CSVCustomTagMatcherPersistenceAdapter;
import persistence.customTags.CustomTagMatcherEntity;
import persistence.link.CSVLinkPersistenceAdapter;
import persistence.link.LinkEntity;
import tag.CustomTagsUseCase;
import tag.TagMatcher;
import tag.TagMatcherRepository;
import tag.TaggingUseCase;
import tag.matcherImplementations.GitHubTagMatcher;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
public class CommandHandler {
private final HashMap<String, Subcommand> subcommands = new HashMap<>();
public CommandHandler() {
this.addSubcommands();
}
public void executeCommand(String[] args) {
if(args.length == 0){
//TODO: print usage
}
var command = subcommands.get(args[0]);
if (command == null) {
throw new CliError("Unknown Command");
}
var output = command.executeSubcommand(Arrays.copyOfRange(args, 1, args.length));
System.out.println(output);
}
private void addSubcommands() {
CategoryRepository categoryRepository =
new CategoryRepository(new CSVCategoryPersistenceAdapter(new GenericCSVDAO<>(new File("category.csv"),
CategoryEntity::new)));
CategoryCliAdapter categoryCliAdapter = new CategoryCliAdapter(new CategoryUseCase(categoryRepository,
new RandomCategoryIdGenerator(
categoryRepository)));
var categoryCommands = new CategoryCommands(categoryCliAdapter);
subcommands.put(categoryCommands.getSubcommand(), categoryCommands);
LinkRepository linkRepository =
new LinkRepository(new CSVLinkPersistenceAdapter(new GenericCSVDAO<>(new File("links.csv"),
LinkEntity::new)));
Set<TagMatcher> staticTagMatchers = Set.of(new GitHubTagMatcher());
TagMatcherRepository tagMatcherRepository =
new TagMatcherRepository(new CSVCustomTagMatcherPersistenceAdapter(new GenericCSVDAO<>(
new File("customtags.csv"),
CustomTagMatcherEntity::new)), staticTagMatchers);
TaggingUseCase taggingUseCase =
new TaggingUseCase(tagMatcherRepository, new RandomLinkIdGenerator(linkRepository));
LinkCliAdapter linkCliAdapter =
new LinkCliAdapter(new LinkUseCase(linkRepository,
categoryRepository,
taggingUseCase,
new RandomLinkIdGenerator(linkRepository)));
var linkCommands = new LinkCommands(linkCliAdapter);
subcommands.put(linkCommands.getSubcommand(), linkCommands);
TagCommands tagCommands =
new TagCommands(new CustomTagsCliAdapter(new CustomTagsUseCase(tagMatcherRepository)));
subcommands.put(tagCommands.getSubcommand(), tagCommands);
}
}

View File

@ -10,12 +10,11 @@ import java.io.File;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
TagName test = new TagName("ds");
var csvCategoryPersistenceAdapter =
new CSVCategoryPersistenceAdapter(new GenericCSVDAO<CategoryEntity>(new File("dsa"),
CategoryEntity::new));
System.out.println(test); CommandHandler commandHandler = new CommandHandler();
commandHandler.executeCommand(args);
} }
} }

View File

@ -21,6 +21,17 @@ public class GenericCSVDAO<T extends CSVSerializable> implements GenericDAO<T> {
public GenericCSVDAO(File file, Function<String[], T> constructor) { public GenericCSVDAO(File file, Function<String[], T> constructor) {
this.file = file; this.file = file;
this.constructor = constructor; this.constructor = constructor;
createFileIfMissing();
}
private void createFileIfMissing() {
if (file.exists()) return;
try {
file.createNewFile();
}
catch (IOException e) {
throw new PersistenceError("Could not create the file " + file.getAbsolutePath());
}
} }
public Set<T> getALl() { public Set<T> getALl() {
@ -31,7 +42,7 @@ public class GenericCSVDAO<T extends CSVSerializable> implements GenericDAO<T> {
} }
} }
catch (IOException e) { catch (IOException e) {
e.printStackTrace(); throw new PersistenceError("Something went wrong while reading from file " + file.getAbsolutePath());
} }
return lines return lines
@ -55,7 +66,7 @@ public class GenericCSVDAO<T extends CSVSerializable> implements GenericDAO<T> {
bufferedWriter.newLine(); bufferedWriter.newLine();
} }
catch (IOException e) { catch (IOException e) {
e.printStackTrace(); throw new PersistenceError("Something went wrong while writing to file " + file.getAbsolutePath());
} }
} }
@ -65,7 +76,7 @@ public class GenericCSVDAO<T extends CSVSerializable> implements GenericDAO<T> {
bufferedWriter.write(""); bufferedWriter.write("");
} }
catch (IOException e) { catch (IOException e) {
e.printStackTrace(); throw new PersistenceError("Something went wrong while writing to file " + file.getAbsolutePath());
} }
} }
} }

View File

@ -0,0 +1,8 @@
package persistence;
public class PersistenceError extends RuntimeException {
public PersistenceError(String message) {
super(message);
}
}

View File

@ -1,6 +1,7 @@
package cli.link; package cli.link;
import category.CategoryName; import category.CategoryName;
import link.LinkDto;
import link.LinkUrl; import link.LinkUrl;
import link.LinkUseCase; import link.LinkUseCase;
import user.Username; import user.Username;
@ -21,4 +22,8 @@ public class LinkCliAdapter {
categoryNames.stream().map(CategoryName::new).collect(Collectors.toSet()), categoryNames.stream().map(CategoryName::new).collect(Collectors.toSet()),
new Username(creator)); new Username(creator));
} }
public Set<String> getLinks() {
return linkUseCase.getLinks().stream().map(LinkDto::toString).collect(Collectors.toSet());
}
} }

View File

@ -22,7 +22,7 @@ public class CategoryEntity implements CSVSerializable {
} }
public CategoryEntity(Category category) { public CategoryEntity(Category category) {
this(category.getName().toString(), category.getId().id()); this(category.getName().getName(), category.getId().id());
} }
public Category toCategory() { public Category toCategory() {
@ -36,7 +36,7 @@ public class CategoryEntity implements CSVSerializable {
@Override @Override
public String toCSVString() { public String toCSVString() {
return name + CSVSerializable.seperator + Integer.toString(id); return name.toString() + CSVSerializable.seperator + Integer.toString(id);
} }
@Override @Override

View File

@ -22,11 +22,11 @@ public class CSVLinkPersistenceAdapter implements PersistenceAdapter<Link> {
@Override @Override
public void add(Link link) { public void add(Link link) {
linkDAO.remove(new LinkEntity(link)); linkDAO.add(new LinkEntity(link));
} }
@Override @Override
public void remove(Link link) { public void remove(Link link) {
linkDAO.add(new LinkEntity(link)); linkDAO.remove(new LinkEntity(link));
} }
} }

View File

@ -12,12 +12,6 @@ public class TagEntity {
private final String name; private final String name;
private Optional<String> additionalData = Optional.empty(); private Optional<String> additionalData = Optional.empty();
public TagEntity(String name, Optional<String> additionalData) {
this.name = name;
this.additionalData = additionalData;
}
public TagEntity(String name, String additionalData) { public TagEntity(String name, String additionalData) {
this.name = name; this.name = name;
this.additionalData = Optional.of(additionalData); this.additionalData = Optional.of(additionalData);

View File

@ -0,0 +1,16 @@
package persistence.category;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CategoryEntityTest {
@Test
void categoryConversionWorks() {
var sut = new CategoryEntity("categoryName", 99);
assertEquals(sut,new CategoryEntity(sut.toCategory()));
}
}

View File

@ -7,7 +7,7 @@ public class CategoryUseCase {
private final CategoryRepository categoryRepository; private final CategoryRepository categoryRepository;
private final CategoryIdGenerator categoryIdGenerator; private final CategoryIdGenerator categoryIdGenerator;
CategoryUseCase(final CategoryRepository categoryRepository, final CategoryIdGenerator idGenerator) { public CategoryUseCase(final CategoryRepository categoryRepository, final CategoryIdGenerator idGenerator) {
this.categoryRepository = categoryRepository; this.categoryRepository = categoryRepository;
this.categoryIdGenerator = idGenerator; this.categoryIdGenerator = idGenerator;
} }

View File

@ -0,0 +1,11 @@
package link;
import category.Category;
import tag.Tag;
import user.Username;
import java.util.Set;
public record LinkDto(Username creator, LinkUrl url, Set<Category> categories, Set<Tag> tags) {
}

View File

@ -2,6 +2,7 @@ package link;
import category.CategoryName; import category.CategoryName;
import category.CategoryRepository; import category.CategoryRepository;
import exeptions.CategroyDoesNotExist;
import exeptions.URLIsNotReachable; import exeptions.URLIsNotReachable;
import tag.TaggingUseCase; import tag.TaggingUseCase;
import user.Username; import user.Username;
@ -43,4 +44,20 @@ public class LinkUseCase {
linkRepository.add(link); linkRepository.add(link);
} }
public Set<LinkDto> getLinks() {
return linkRepository
.getAll()
.stream()
.map(link -> new LinkDto(link.getCreator(),
link.getUrl(),
link
.getCategoryIds()
.stream()
.map(categoryRepository::getById)
.map(optional -> optional.orElseThrow(() -> new CategroyDoesNotExist(
"A Category for a certain id does not exits. You must create it first.")))
.collect(Collectors.toSet()),
link.getTags()))
.collect(Collectors.toSet());
}
} }

View File

@ -1,19 +1,21 @@
package tag; package tag;
import link.LinkUrl; import link.LinkUrl;
import link.RandomLinkIdGenerator;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class TaggingUseCase { public class TaggingUseCase {
TagMatcherRepository tagMatcherRepository; TagMatcherRepository tagMatcherRepository;
public TaggingUseCase(TagMatcherRepository tagMatcherRepository) { public TaggingUseCase(TagMatcherRepository tagMatcherRepository, RandomLinkIdGenerator randomLinkIdGenerator) {
this.tagMatcherRepository = tagMatcherRepository; this.tagMatcherRepository = tagMatcherRepository;
} }
public Set<Tag> getTagsFor(LinkUrl url) { public Set<Tag> getTagsFor(LinkUrl url) {
Set<Tag> result = Set.of(); Set<Tag> result = new HashSet<>();
tagMatcherRepository.getTagMatchers().forEach(tagMatcher -> tagMatcher.ifMatches(url).addTo(result)); tagMatcherRepository.getTagMatchers().forEach(tagMatcher -> tagMatcher.ifMatches(url).addTo(result));
return result; return result;
} }

View File

@ -19,6 +19,11 @@ public class Category {
return name; return name;
} }
@Override
public String toString() {
return name.toString();
}
public CategoryId getId() { public CategoryId getId() {
return id; return id;
} }

View File

@ -41,4 +41,9 @@ public class CategoryName {
public int hashCode() { public int hashCode() {
return name != null ? name.hashCode() : 0; return name != null ? name.hashCode() : 0;
} }
@Override
public String toString() {
return name;
}
} }

View File

@ -53,6 +53,15 @@ public class Link {
return url.equals(link.url); return url.equals(link.url);
} }
@Override
public String toString() {
return url +
" created by =" + creator +
", categoryIds=" + categoryIds +
", tags=" + tags +
'}';
}
@Override @Override
public int hashCode() { public int hashCode() {
int result = id.hashCode(); int result = id.hashCode();

View File

@ -7,13 +7,14 @@ import exeptions.LinkAlreadyExists;
import exeptions.LinkDoesNotExist; import exeptions.LinkDoesNotExist;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
public class LinkRepository { public class LinkRepository {
final private CustomSet<Link> links; final private CustomSet<Link> links;
public LinkRepository(PersistenceAdapter<Link> linkPersistenceAdapter) { public LinkRepository(PersistenceAdapter<Link> linkPersistenceAdapter) {
this.links = new CustomSetPersistenceDecorator(linkPersistenceAdapter); this.links = new CustomSetPersistenceDecorator<>(linkPersistenceAdapter);
} }
public Optional<Link> getById(LinkId id) { public Optional<Link> getById(LinkId id) {
@ -41,6 +42,10 @@ public class LinkRepository {
links.add(link); links.add(link);
} }
public Set<Link> getAll() {
return links.getSet();
}
private void remove(Link link) { private void remove(Link link) {
links.remove(link); links.remove(link);
} }

View File

@ -5,7 +5,7 @@ import java.util.Optional;
public class Tag { public class Tag {
private TagName name; private TagName name;
private Optional<String> additionalData; private Optional<String> additionalData = Optional.empty();
public Tag(TagName name) { public Tag(TagName name) {
this.name = name; this.name = name;
@ -21,6 +21,11 @@ public class Tag {
this.additionalData = additionalData; this.additionalData = additionalData;
} }
@Override
public String toString() {
return "Tag: " + name + " " + additionalData.orElse("");
}
public TagName getName() { public TagName getName() {
return name; return name;
} }

View File

@ -9,4 +9,9 @@ public record TagName(String name) {
throw new IllegalValueObjectArgument("A Tag name must be a valid non-empty string."); throw new IllegalValueObjectArgument("A Tag name must be a valid non-empty string.");
} }
} }
@Override
public String toString() {
return name;
}
} }

View File

@ -9,4 +9,9 @@ public record Username(String username) {
throw new IllegalValueObjectArgument("A username must be a valid non-empty string."); throw new IllegalValueObjectArgument("A username must be a valid non-empty string.");
} }
} }
@Override
public String toString() {
return username;
}
} }