initial commit

This commit is contained in:
2025-12-09 15:40:47 +01:00
commit 91c731fef4
28 changed files with 690 additions and 0 deletions

39
.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
.kotlin
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

9
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="file://$USER_HOME$/src/main/java" charset="UTF-8" />
<file url="file://$USER_HOME$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" default="true" project-jdk-name="22" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

3
kontakty.txt Normal file
View File

@@ -0,0 +1,3 @@
Jan;Novak;1990-05-12;jan.novak@email.com;777123456
Petra;Svobodova;1985-11-02;petra.svobodova@email.com;777654321
Karel;Dvorak;2000-07-20;karel.dvorak@email.com;777987654

25
pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.jzitnik</groupId>
<artifactId>commandmezabijejednou</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
</dependencies>
</project>

9
quotes.txt Normal file
View File

@@ -0,0 +1,9 @@
“Matematika je jazyk, kterým Bůh napsal vesmír.” Galileo Galilei
“Neexistuje žádná krása bez harmonie.” Plato
“Život je jako jízda na kole. Abys udržel rovnováhu, musíš se pohybovat vpřed.” Albert Einstein
“V každém problému se skrývá řešení.” Neznámý
“Pranostika: Na svatého Jiří přijde jaro brzy, nebo později zima zhoustne.”
E=mc^2
F = ma
a^2 + b^2 = c^2
∑_{i=1}^{n} i = n(n+1)/2

View File

@@ -0,0 +1,95 @@
package cz.jzitnik;
import cz.jzitnik.annotations.CommandImpl;
import cz.jzitnik.commands.models.Command;
import cz.jzitnik.services.ClassFactory;
import cz.jzitnik.services.CommandHistory;
import cz.jzitnik.services.CommandInvoker;
import org.reflections.Reflections;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
public class Console implements Runnable {
private final CommandInvoker invoker = new CommandInvoker();
private final ClassFactory factory = new ClassFactory();
@Override
public void run() {
factory.load();
loadCommands();
Scanner sc = new Scanner(System.in);
System.out.println("Type 'help' for commands.");
boolean running = true;
while (running) {
System.out.print("-> ");
String input = sc.nextLine();
((CommandHistory) factory.get(CommandHistory.class)).add(input);
if (input.equals("stop")) {
running = false;
continue;
}
if (input.equals("help")) {
HashMap<String, Command> commands = invoker.getCommands();
System.out.println(commands.keySet());
continue;
}
String[] parts = input.split(" ", 2);
String cmd = parts[0];
String args2 = parts.length > 1 ? parts[1] : "";
String result = invoker.execute(cmd, args2);
System.out.println(result);
}
sc.close();
}
private void loadCommands() {
Reflections reflections = new Reflections("cz.jzitnik.commands");
List<? extends Class<? extends Command>> entityClasses =
reflections.getTypesAnnotatedWith(CommandImpl.class).stream()
.filter(Command.class::isAssignableFrom)
.map(i -> (Class<? extends Command>) i)
.toList();
for (Class<? extends Command> command : entityClasses) {
CommandImpl annotation = command.getAnnotation(CommandImpl.class);
for (var constructor : command.getDeclaredConstructors()) {
var paramTypes = constructor.getParameterTypes();
var params = new Object[paramTypes.length];
boolean suitable = true;
for (int i = 0; i < paramTypes.length; i++) {
Class<?> type = paramTypes[i];
if (factory.contains(type))
params[i] = factory.get(type);
else {
suitable = false;
break;
}
}
if (suitable) {
constructor.setAccessible(true);
try {
Command instance = (Command) constructor.newInstance(params);
invoker.register(annotation.value(), instance);
} catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
break; // Found a matching constructor, go to next class
}
}
}
}
}

View File

@@ -0,0 +1,9 @@
package cz.jzitnik;
public class Main {
public static void main(String[] args) {
Console console = new Console();
console.run();
}
}

View File

@@ -0,0 +1,12 @@
package cz.jzitnik.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CommandImpl {
String value();
}

View File

@@ -0,0 +1,11 @@
package cz.jzitnik.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Config {
}

View File

@@ -0,0 +1,11 @@
package cz.jzitnik.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Data {
}

View File

@@ -0,0 +1,52 @@
package cz.jzitnik.commands;
import cz.jzitnik.annotations.CommandImpl;
import cz.jzitnik.commands.models.Command;
import cz.jzitnik.factory.Contact;
import cz.jzitnik.repository.ContactRepository;
@CommandImpl("contacts <operation;parameters>")
public class ContactCommand implements Command {
private final ContactRepository cm;
public ContactCommand(ContactRepository cm) {
this.cm = cm;
}
@Override
public String execute(String args) {
// `args` ve formátu:
// add;jmeno;prijmeni;datum;email;telefon
// delete;telefon
// searchln;prijmeni
// searchph;telefon
// edit;staryTelefon;jmeno;prijmeni;datum;email;telefon
String[] p = args.split(";");
return switch (p[0]) {
case "add" -> {
Contact c = new Contact();
c.firstName = p[1];
c.lastName = p[2];
c.birthdate = p[3];
c.email = p[4];
c.phone = p[5];
yield cm.add(c);
}
case "delete" -> cm.delete(p[1]);
case "searchln" -> cm.searchLastName(p[1]);
case "searchph" -> cm.searchPhone(p[1]);
case "edit" -> {
Contact c = new Contact();
c.firstName = p[2];
c.lastName = p[3];
c.birthdate = p[4];
c.email = p[5];
c.phone = p[6];
yield cm.edit(p[1], c);
}
default -> String.join("\n", cm.getContacts().stream().map(Contact::toString).toList());
};
}
}

View File

@@ -0,0 +1,14 @@
package cz.jzitnik.commands;
import cz.jzitnik.annotations.CommandImpl;
import cz.jzitnik.commands.models.Command;
import java.time.LocalDateTime;
@CommandImpl("datetime")
public class DateTimeCommand implements Command {
@Override
public String execute(String args) {
return LocalDateTime.now().toString();
}
}

View File

@@ -0,0 +1,20 @@
package cz.jzitnik.commands;
import cz.jzitnik.annotations.CommandImpl;
import cz.jzitnik.commands.models.Command;
import cz.jzitnik.services.CommandHistory;
@CommandImpl("history")
public class HistoryCommand implements Command {
private final CommandHistory history;
public HistoryCommand(CommandHistory h) {
this.history = h;
}
@Override
public String execute(String args) {
return String.join("\n", history.getAll());
}
}

View File

@@ -0,0 +1,44 @@
package cz.jzitnik.commands;
import cz.jzitnik.annotations.CommandImpl;
import cz.jzitnik.commands.models.Command;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@CommandImpl("quadratic Ax^2+Bx+C")
public class QuadraticCommand implements Command {
@Override
public String execute(String eq) {
try {
eq = eq.replace(" ", "");
Pattern p = Pattern.compile("([+-]?\\d*)x\\^2([+-]\\d*)x([+-]\\d+)");
Matcher m = p.matcher(eq);
if (!m.matches()) {
return "Neplatný formát. Example: 4x^2+3x-2";
}
double A = m.group(1).equals("") || m.group(1).equals("+") ? 1 :
m.group(1).equals("-") ? -1 : Double.parseDouble(m.group(1));
double B = Double.parseDouble(m.group(2));
double C = Double.parseDouble(m.group(3));
double D = B * B - 4 * A * C;
if (D < 0) {
return "Žádné reálné kořeny.";
}
double x1 = (-B + Math.sqrt(D)) / (2 * A);
double x2 = (-B - Math.sqrt(D)) / (2 * A);
return "Kořeny: " + x1 + ", " + x2;
} catch (Exception e) {
return "Error parsing equation.";
}
}
}

View File

@@ -0,0 +1,32 @@
package cz.jzitnik.commands;
import cz.jzitnik.annotations.CommandImpl;
import cz.jzitnik.commands.models.Command;
import cz.jzitnik.config.models.QuoteConfig;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Random;
@CommandImpl("quotes")
public class QuoteCommand implements Command {
private final List<String> quotes;
public QuoteCommand(QuoteConfig config) {
List<String> temp;
try {
temp = Files.readAllLines(Paths.get(config.getFilePath()));
} catch (Exception e) {
temp = List.of("No quotes found.");
}
quotes = temp;
}
@Override
public String execute(String args) {
Random r = new Random();
return quotes.get(r.nextInt(quotes.size()));
}
}

View File

@@ -0,0 +1,5 @@
package cz.jzitnik.commands.models;
public interface Command {
String execute(String args);
}

View File

@@ -0,0 +1,12 @@
package cz.jzitnik.config;
import cz.jzitnik.annotations.Config;
import cz.jzitnik.config.models.ContactRepositoryConfig;
@Config
public class ContactRepositoryConfigImpl implements ContactRepositoryConfig {
@Override
public String getFilePath() {
return "kontakty.txt";
}
}

View File

@@ -0,0 +1,12 @@
package cz.jzitnik.config;
import cz.jzitnik.annotations.Config;
import cz.jzitnik.config.models.QuoteConfig;
@Config
public class QuoteConfigImpl implements QuoteConfig {
@Override
public String getFilePath() {
return "quotes.txt";
}
}

View File

@@ -0,0 +1,5 @@
package cz.jzitnik.config.models;
public interface ContactRepositoryConfig {
String getFilePath();
}

View File

@@ -0,0 +1,5 @@
package cz.jzitnik.config.models;
public interface QuoteConfig {
String getFilePath();
}

View File

@@ -0,0 +1,25 @@
package cz.jzitnik.factory;
public class Contact {
public String firstName;
public String lastName;
public String birthdate;
public String email;
public String phone;
@Override
public String toString() {
return firstName + ";" + lastName + ";" + birthdate + ";" + email + ";" + phone;
}
public static Contact fromString(String s) {
String[] p = s.split(";");
Contact c = new Contact();
c.firstName = p[0];
c.lastName = p[1];
c.birthdate = p[2];
c.email = p[3];
c.phone = p[4];
return c;
}
}

View File

@@ -0,0 +1,86 @@
package cz.jzitnik.repository;
import cz.jzitnik.annotations.Data;
import cz.jzitnik.config.models.ContactRepositoryConfig;
import cz.jzitnik.factory.Contact;
import java.io.*;
import java.util.*;
@Data
public class ContactRepository {
private final String filePath;
private final List<Contact> contacts = new ArrayList<>();
public List<Contact> getContacts() {
return contacts;
}
public ContactRepository(ContactRepositoryConfig config) {
this.filePath = config.getFilePath();
load();
}
private void load() {
try {
File f = new File(filePath);
if (!f.exists()) return;
try (Scanner sc = new Scanner(f)) {
while (sc.hasNextLine()) {
contacts.add(Contact.fromString(sc.nextLine()));
}
}
} catch (Exception ignored) {}
}
private void save() {
try (PrintWriter pw = new PrintWriter(filePath)) {
for (Contact c : contacts) pw.println(c);
} catch (Exception ignored) {}
}
public String add(Contact c) {
contacts.add(c);
save();
return "Contact added.";
}
public String edit(String phone, Contact updated) {
for (Contact c : contacts) {
if (c.phone.equals(phone)) {
c.firstName = updated.firstName;
c.lastName = updated.lastName;
c.birthdate = updated.birthdate;
c.email = updated.email;
c.phone = updated.phone;
save();
return "Contact updated.";
}
}
return "Contact not found.";
}
public String delete(String phone) {
boolean removed = contacts.removeIf(c -> c.phone.equals(phone));
save();
return removed ? "Contact removed." : "Contact not found.";
}
public String searchLastName(String ln) {
StringBuilder sb = new StringBuilder();
contacts.stream()
.filter(c -> c.lastName.equalsIgnoreCase(ln))
.forEach(c -> sb.append(c).append("\n"));
return sb.length() == 0 ? "Not found." : sb.toString();
}
public String searchPhone(String ph) {
StringBuilder sb = new StringBuilder();
contacts.stream()
.filter(c -> c.phone.equals(ph))
.forEach(c -> sb.append(c).append("\n"));
return sb.length() == 0 ? "Not found." : sb.toString();
}
}

View File

@@ -0,0 +1,78 @@
package cz.jzitnik.services;
import cz.jzitnik.annotations.Config;
import cz.jzitnik.annotations.Data;
import org.reflections.Reflections;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Set;
public class ClassFactory {
private final HashMap<Class<?>, Object> instances = new HashMap<>();
public HashMap<Class<?>, Object> getInstances() {
return instances;
}
public boolean contains(Class<?> clazz) {
return instances.keySet().stream().anyMatch(clazzIn -> clazz.isAssignableFrom(clazzIn));
}
public Object get(Class<?> clazz) {
for (Class<?> clazzInDb : instances.keySet()) {
if (clazz.isAssignableFrom(clazzInDb)) {
return instances.get(clazzInDb);
}
}
return null;
}
public void load() {
Reflections reflections = new Reflections("cz.jzitnik");
Set<Class<?>> configs = reflections.getTypesAnnotatedWith(Config.class);
for (Class<?> config : configs) {
try {
var instance = config.getDeclaredConstructor().newInstance();
instances.put(config, instance);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
Set<Class<?>> entityClasses = reflections.getTypesAnnotatedWith(Data.class);
for (Class<?> clazz : entityClasses) {
for (var constructor : clazz.getDeclaredConstructors()) {
var paramTypes = constructor.getParameterTypes();
var params = new Object[paramTypes.length];
boolean suitable = true;
for (int i = 0; i < paramTypes.length; i++) {
Class<?> type = paramTypes[i];
if (contains(type))
params[i] = get(type);
else {
suitable = false;
break;
}
}
if (suitable) {
constructor.setAccessible(true);
try {
Object instance = constructor.newInstance(params);
instances.put(clazz, instance);
} catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
break; // Found a matching constructor, go to next class
}
}
}
}
}

View File

@@ -0,0 +1,19 @@
package cz.jzitnik.services;
import cz.jzitnik.annotations.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class CommandHistory {
private final List<String> list = new ArrayList<>();
public void add(String cmd) {
list.add(cmd);
}
public List<String> getAll() {
return list;
}
}

View File

@@ -0,0 +1,35 @@
package cz.jzitnik.services;
import cz.jzitnik.commands.models.Command;
import java.util.HashMap;
public class CommandInvoker {
private final HashMap<String, Command> commands = new HashMap<>();
public HashMap<String, Command> getCommands() {
return commands;
}
private Command get(String name) {
for (String cmd : commands.keySet()) {
if ((cmd + " ").split(" ")[0].equals(name)) {
return commands.get(cmd);
}
}
return null;
}
public void register(String name, Command cmd) {
commands.put(name, cmd);
}
public String execute(String name, String args) {
Command cmd = get(name);
if (cmd != null) {
return cmd.execute(args);
}
return "Unknown command.";
}
}