diff --git a/config/init_db.sql b/config/init_db.sql new file mode 100644 index 00000000..88bad824 --- /dev/null +++ b/config/init_db.sql @@ -0,0 +1,13 @@ +CREATE TABLE resume ( + uuid CHAR(36) PRIMARY KEY NOT NULL, + full_name TEXT NOT NULL +); + +CREATE TABLE contact ( + id SERIAL, + resume_uuid CHAR(36) NOT NULL REFERENCES resume (uuid) ON DELETE CASCADE, + type TEXT NOT NULL, + value TEXT NOT NULL +); +CREATE UNIQUE INDEX contact_uuid_type_index + ON contact (resume_uuid, type); \ No newline at end of file diff --git a/config/resumes.properties b/config/resumes.properties new file mode 100644 index 00000000..5714d470 --- /dev/null +++ b/config/resumes.properties @@ -0,0 +1,4 @@ +storage.dir=C:/Java/FileStorage +db.url=jdbc:postgresql://localhost:5432/resumes +db.user=postgres +db.password=albpostgre \ No newline at end of file diff --git a/lesson/lesson1.md b/lesson/lesson1.md index a1b848e6..08c9df94 100644 --- a/lesson/lesson1.md +++ b/lesson/lesson1.md @@ -79,7 +79,7 @@ ![finish](https://user-images.githubusercontent.com/29703461/38275669-3e621614-379b-11e8-8b3a-8e0a3ad4c65c.png) -- Реализуйте класс `ArrayStorage`, организовав хранение резюме на основе массива с методами `save, get, delete, size, clear, getAll` +- Реализуйте класс `com.urise.webapp.storage.ArrayStorage`, организовав хранение резюме на основе массива с методами `save, get, delete, size, clear, getAll` - Храните все резюме в начале `storage` (без дырок в виде `null`), чтобы не перебирать каждый раз все 10000 элементов ``` Схема хранения резюме в массиве storage (в элементах от 0 до size-1 отсутствуют null): @@ -88,7 +88,7 @@ r1, r2, r3,..., rn, null, null,..., null <----- size -----> <------- storage.length (10000) -------> ``` -- Протестируйте вашу реализацию с помощью классов `MainArray.main()` и `MainTestArrayStorage.main()` +- Протестируйте вашу реализацию с помощью классов `com.urise.webapp.MainArray.main()` и `com.urise.webapp.MainTestArrayStorage.main()` - Изучите дополнительные материалы по IntelliJ IDEA: - [Idea Wiki](https://github.com/JavaOPs/topjava/wiki/IDEA) ([поставьте кодировку UTF-8](https://github.com/JavaOPs/topjava/wiki/IDEA#Поставить-кодировку-utf-8), [поменяйте шрифт по умолчанию на DejaVu](https://github.com/JavaOPs/topjava/wiki/IDEA#Поменять-фонт-по-умолчанию-dejavu)) - [Руководство пользователя IntelliJ IDEA. Отладчик](http://info.javarush.ru/idea_help/2014/01/22/Руководство-пользователя-IntelliJ-IDEA-Отладчик-.html) @@ -112,7 +112,7 @@ r1, r2, r3,..., rn, null, null,..., null 4. Не злоупотребляйте пустыми строками. Они используются нечасто для логического отделения больших кусков кода. 5. Удаляйте неиспользуемые импорты (`Ctrl + Alt + O`) 5. Не игнорируй подсказки IDEA (подсвечивает) -6. `Resume r` — давай переменным осмысленные имена, например `resume`. `r` допустимо в коротких циклах и лямбдах. +6. `com.urise.webapp.model.Resume r` — давай переменным осмысленные имена, например `resume`. `r` допустимо в коротких циклах и лямбдах. 7. В методе `clear()` обнуление массива предполагает именно обнуление (null), а не создание нового # Дополнительно (как учиться программированию) diff --git a/lib/postgresql-42.2.1.jar b/lib/postgresql-42.2.1.jar new file mode 100644 index 00000000..e934846c Binary files /dev/null and b/lib/postgresql-42.2.1.jar differ diff --git a/src/ArrayStorage.java b/src/ArrayStorage.java deleted file mode 100644 index 7aff0388..00000000 --- a/src/ArrayStorage.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Array based storage for Resumes - */ -public class ArrayStorage { - Resume[] storage = new Resume[10000]; - - void clear() { - } - - void save(Resume r) { - } - - Resume get(String uuid) { - return null; - } - - void delete(String uuid) { - } - - /** - * @return array, contains only Resumes in storage (without null) - */ - Resume[] getAll() { - return new Resume[0]; - } - - int size() { - return 0; - } -} diff --git a/src/MainArray.java b/src/MainArray.java deleted file mode 100644 index b1cb33b7..00000000 --- a/src/MainArray.java +++ /dev/null @@ -1,71 +0,0 @@ -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -/** - * Interactive test for ArrayStorage implementation - * (just run, no need to understand) - */ -public class MainArray { - private final static ArrayStorage ARRAY_STORAGE = new ArrayStorage(); - - public static void main(String[] args) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - Resume r; - while (true) { - System.out.print("Введите одну из команд - (list | save uuid | delete uuid | get uuid | clear | exit): "); - String[] params = reader.readLine().trim().toLowerCase().split(" "); - if (params.length < 1 || params.length > 2) { - System.out.println("Неверная команда."); - continue; - } - String uuid = null; - if (params.length == 2) { - uuid = params[1].intern(); - } - switch (params[0]) { - case "list": - printAll(); - break; - case "size": - System.out.println(ARRAY_STORAGE.size()); - break; - case "save": - r = new Resume(); - r.uuid = uuid; - ARRAY_STORAGE.save(r); - printAll(); - break; - case "delete": - ARRAY_STORAGE.delete(uuid); - printAll(); - break; - case "get": - System.out.println(ARRAY_STORAGE.get(uuid)); - break; - case "clear": - ARRAY_STORAGE.clear(); - printAll(); - break; - case "exit": - return; - default: - System.out.println("Неверная команда."); - break; - } - } - } - - static void printAll() { - Resume[] all = ARRAY_STORAGE.getAll(); - System.out.println("----------------------------"); - if (all.length == 0) { - System.out.println("Empty"); - } else { - for (Resume r : all) { - System.out.println(r); - } - } - System.out.println("----------------------------"); - } -} \ No newline at end of file diff --git a/src/MainTestArrayStorage.java b/src/MainTestArrayStorage.java deleted file mode 100644 index b15b81e2..00000000 --- a/src/MainTestArrayStorage.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Test for your ArrayStorage implementation - */ -public class MainTestArrayStorage { - static final ArrayStorage ARRAY_STORAGE = new ArrayStorage(); - - public static void main(String[] args) { - Resume r1 = new Resume(); - r1.uuid = "uuid1"; - Resume r2 = new Resume(); - r2.uuid = "uuid2"; - Resume r3 = new Resume(); - r3.uuid = "uuid3"; - - ARRAY_STORAGE.save(r1); - ARRAY_STORAGE.save(r2); - ARRAY_STORAGE.save(r3); - - System.out.println("Get r1: " + ARRAY_STORAGE.get(r1.uuid)); - System.out.println("Size: " + ARRAY_STORAGE.size()); - - System.out.println("Get dummy: " + ARRAY_STORAGE.get("dummy")); - - printAll(); - ARRAY_STORAGE.delete(r1.uuid); - printAll(); - ARRAY_STORAGE.clear(); - printAll(); - - System.out.println("Size: " + ARRAY_STORAGE.size()); - } - - static void printAll() { - System.out.println("\nGet All"); - for (Resume r : ARRAY_STORAGE.getAll()) { - System.out.println(r); - } - } -} diff --git a/src/Resume.java b/src/Resume.java deleted file mode 100644 index 8de4e4b8..00000000 --- a/src/Resume.java +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Initial resume class - */ -public class Resume { - - // Unique identifier - String uuid; - - @Override - public String toString() { - return uuid; - } -} diff --git a/src/com/urise/webapp/Config.java b/src/com/urise/webapp/Config.java new file mode 100644 index 00000000..e8ce93ff --- /dev/null +++ b/src/com/urise/webapp/Config.java @@ -0,0 +1,42 @@ +package com.urise.webapp; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.Properties; + +public class Config { + protected static final File PROPS = new File(".\\storage\\resume.properties"); + private static final Config INSTANCE = new Config(); + private Properties props = new Properties(); + private File storageDir; + + private Config() { + try (InputStream is = new FileInputStream("./config/resumes.properties")) { + props.load(is); + storageDir = new File (props.getProperty("storage.dir")); + + } catch (IOException e) { + throw new IllegalStateException("Invalid config file " +PROPS.getAbsolutePath()); + } + } + + public static Config getInstance() { + return INSTANCE; + } + + public File getStorageDir() { + return storageDir; + } + public String getDbUrl (){ + return props.getProperty("db.url"); + } + public String getDbUser (){ + return props.getProperty("db.user"); + } + public String getDbPassword (){ + return props.getProperty("db.password"); + } +} diff --git a/src/com/urise/webapp/MainDate.java b/src/com/urise/webapp/MainDate.java new file mode 100644 index 00000000..40edae2d --- /dev/null +++ b/src/com/urise/webapp/MainDate.java @@ -0,0 +1,19 @@ +package com.urise.webapp; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.util.Calendar; +import java.util.Date; + +public class MainDate { + public static void main(String[] args) { + Date date = new Date(); + System.out.println(date.getTime()); + Calendar cal = Calendar.getInstance(); + System.out.println(cal.getTime()); + LocalDate ld = LocalDate.now(); + SimpleDateFormat sdf = new SimpleDateFormat("YY/MM/dd"); + System.out.println(sdf.format(cal.getTime())); + + } +} diff --git a/src/com/urise/webapp/MainFile.java b/src/com/urise/webapp/MainFile.java new file mode 100644 index 00000000..69a682ba --- /dev/null +++ b/src/com/urise/webapp/MainFile.java @@ -0,0 +1,38 @@ +package com.urise.webapp; + +import java.io.File; +import java.io.IOException; + +public class MainFile { + static StringBuilder sb = new StringBuilder(); + + public static void main(String[] args) { + /*текущий каталог*/ + File dir = new File(".\\."); + try { + findFiles(dir); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void findFiles(File file) throws IOException { + if (file.isDirectory()) { + System.out.println(sb.toString() + "Directory: " + file.getName()); + File[] list = file.listFiles(); + if (list == null) { + System.out.println("Directory is empty!"); + return; + } + sb.append(" "); + for (int i = list.length; --i >= 0; ) { + findFiles(list[i]); + } + sb.delete(sb.length() - 1, sb.length()); + + } else { + System.out.println(sb.toString() + file.getName()); + } + } + +} diff --git a/src/com/urise/webapp/MainReflection.java b/src/com/urise/webapp/MainReflection.java new file mode 100644 index 00000000..a3ff1f3b --- /dev/null +++ b/src/com/urise/webapp/MainReflection.java @@ -0,0 +1,17 @@ +package com.urise.webapp; + +import com.urise.webapp.model.Resume; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class MainReflection { + public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Resume test = new Resume("test"); + System.out.println(test); + Method method = test.getClass().getMethod("toString"); + System.out.println(method.invoke(test)); + + } + +} \ No newline at end of file diff --git a/src/com/urise/webapp/exception/ExistStorageException.java b/src/com/urise/webapp/exception/ExistStorageException.java new file mode 100644 index 00000000..73fbbf8f --- /dev/null +++ b/src/com/urise/webapp/exception/ExistStorageException.java @@ -0,0 +1,7 @@ +package com.urise.webapp.exception; + +public class ExistStorageException extends StorageException { + public ExistStorageException(String uuid) { + super("Resume " + uuid + " already exist", uuid); + } +} diff --git a/src/com/urise/webapp/exception/NotExistStorageException.java b/src/com/urise/webapp/exception/NotExistStorageException.java new file mode 100644 index 00000000..68164920 --- /dev/null +++ b/src/com/urise/webapp/exception/NotExistStorageException.java @@ -0,0 +1,7 @@ +package com.urise.webapp.exception; + +public class NotExistStorageException extends StorageException { + public NotExistStorageException(String uuid) { + super("Resume " + uuid + " not exist", uuid); + } +} diff --git a/src/com/urise/webapp/exception/StorageException.java b/src/com/urise/webapp/exception/StorageException.java new file mode 100644 index 00000000..d132360d --- /dev/null +++ b/src/com/urise/webapp/exception/StorageException.java @@ -0,0 +1,30 @@ +package com.urise.webapp.exception; + +public class StorageException extends RuntimeException { + private final String uuid; + + public StorageException(String message) { + this(message, null, null); + } + + public StorageException(String message, String uuid) { + super(message); + this.uuid = uuid; + } + + public StorageException(String message, Exception e) { + this(message, null, e); + } + + public StorageException(Exception e) { + this(e.getMessage(),e); + } + public StorageException(String message, String uuid, Exception e) { + super(message, e); + this.uuid = uuid; + } + + public String getUuid() { + return uuid; + } +} diff --git a/src/com/urise/webapp/lesson11/Account.java b/src/com/urise/webapp/lesson11/Account.java new file mode 100644 index 00000000..30ea94a5 --- /dev/null +++ b/src/com/urise/webapp/lesson11/Account.java @@ -0,0 +1,21 @@ +package com.urise.webapp.lesson11; + +public class Account { + int balance; + + public Account(int balance) { + this.balance = balance; + } + + public void withdraw(int sum) { + if (sum > balance) { + throw new AccountExc("Exceeded balance amount"); + } + balance = -sum; + } + + public void add(int sum) { + balance += sum; + } + +} diff --git a/src/com/urise/webapp/lesson11/AccountExc.java b/src/com/urise/webapp/lesson11/AccountExc.java new file mode 100644 index 00000000..297eceda --- /dev/null +++ b/src/com/urise/webapp/lesson11/AccountExc.java @@ -0,0 +1,7 @@ +package com.urise.webapp.lesson11; + +public class AccountExc extends RuntimeException { + public AccountExc(String message) { + System.out.println(message); + } +} diff --git a/src/com/urise/webapp/lesson11/TransactMoney.java b/src/com/urise/webapp/lesson11/TransactMoney.java new file mode 100644 index 00000000..1be5fd6d --- /dev/null +++ b/src/com/urise/webapp/lesson11/TransactMoney.java @@ -0,0 +1,35 @@ +package com.urise.webapp.lesson11; + +import static java.lang.Thread.currentThread; + +public class TransactMoney { + public static void main(String[] args) { + TransactMoney tm = new TransactMoney(); + Account a1 = new Account(1000); + Account a2 = new Account(2000); + new Thread(() -> { + System.out.println("Thread " + Thread.currentThread().getName() + " starts transferring money!"); + tm.transferMoney(a1, a2, 500); + System.out.println("Thread " + Thread.currentThread().getName() + " has transferred money!"); + }).start(); + System.out.println("Thread " + Thread.currentThread().getName() + " starts transferring money!"); + tm.transferMoney(a2, a1, 700); + System.out.println("Thread " + Thread.currentThread().getName() + " has transferred money!"); + } + + public void transferMoney(Account a1, Account a2, int sum) { + //dead lock + synchronized (a1) { + try { + currentThread().sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + synchronized (a2) { + a1.withdraw(sum); + a2.add(sum); + } + } + } + +} diff --git a/src/com/urise/webapp/model/AbstractSection.java b/src/com/urise/webapp/model/AbstractSection.java new file mode 100644 index 00000000..b25fe881 --- /dev/null +++ b/src/com/urise/webapp/model/AbstractSection.java @@ -0,0 +1,9 @@ +package com.urise.webapp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.io.Serializable; + +@XmlAccessorType(XmlAccessType.FIELD) +public abstract class AbstractSection implements Serializable { +} diff --git a/src/com/urise/webapp/model/ContactType.java b/src/com/urise/webapp/model/ContactType.java new file mode 100644 index 00000000..b1d18be4 --- /dev/null +++ b/src/com/urise/webapp/model/ContactType.java @@ -0,0 +1,23 @@ +package com.urise.webapp.model; + +public enum ContactType { + PHONE("Тел."), + MOBILE("Мобильный"), + НОMЕ_PHONE("Домашний тел."), + SKYPE("Skype"), + MAIL("Почта"), + LINKEDIN("Профиль LinkedIn"), + GITHUB("Профиль GitHub"), + STATCKOVERFLOW("Профиль Stackoverflow"), + НОMЕ_PAGE("Домашняя страница"); + + private final String title; + + ContactType(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } +} \ No newline at end of file diff --git a/src/com/urise/webapp/model/Link.java b/src/com/urise/webapp/model/Link.java new file mode 100644 index 00000000..fef4fb17 --- /dev/null +++ b/src/com/urise/webapp/model/Link.java @@ -0,0 +1,54 @@ +package com.urise.webapp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.io.Serializable; +import java.util.Objects; + +@XmlAccessorType(XmlAccessType.FIELD) +public class Link implements Serializable { + public static final long serialVersionUID = 1L; + + private String name; + private String url; + + public Link() { + } + + public Link(String name, String url) { + Objects.requireNonNull(name, "name must not be null"); + this.name = name; + this.url = url==null?"":url; + } + + public String getName() { + return name; + } + + public String getUrl() { + return url; + } + + @Override + public String toString() { + return "Link (" + name + ',' + url + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Link link = (Link) o; + + if (!name.equals(link.name)) return false; + return url != null ? url.equals(link.url) : link.url == null; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (url != null ? url.hashCode() : 0); + return result; + } +} diff --git a/src/com/urise/webapp/model/ListSection.java b/src/com/urise/webapp/model/ListSection.java new file mode 100644 index 00000000..c1ab2b85 --- /dev/null +++ b/src/com/urise/webapp/model/ListSection.java @@ -0,0 +1,49 @@ +package com.urise.webapp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + + +public class ListSection extends AbstractSection { + public static final long serialVersionUID = 1L; + private List items; + + public ListSection() { + } + + public ListSection(String... items) { + this(Arrays.asList(items)); + } + + public ListSection(List items) { + Objects.requireNonNull(items, "items must not null"); + this.items = items; + } + + public List getItems() { + return items; + } + + @Override + public String toString() { + return items.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ListSection that = (ListSection) o; + + return items.equals(that.items); + } + + @Override + public int hashCode() { + return items.hashCode(); + } +} diff --git a/src/com/urise/webapp/model/Organization.java b/src/com/urise/webapp/model/Organization.java new file mode 100644 index 00000000..9e164581 --- /dev/null +++ b/src/com/urise/webapp/model/Organization.java @@ -0,0 +1,163 @@ +package com.urise.webapp.model; + +import com.urise.webapp.util.DateUtil; +import com.urise.webapp.util.LocalDateAdapter; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.io.Serializable; +import java.time.LocalDate; +import java.time.Month; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import static com.urise.webapp.util.DateUtil.NOW; + +@XmlAccessorType(XmlAccessType.FIELD) +public class Organization implements Serializable { + private Link homePage; + private List positions = new ArrayList<>(); + + public Organization() { + } + + public Organization(String name, String url, Position... positions) { + this(new Link(name, url), Arrays.asList(positions)); + } + + public Organization(String name, String url, List positions) { + this(new Link(name, url), positions); + } + + public Organization(Link homePage, List positions) { + this.homePage = homePage; + this.positions = positions; + } + + @Override + public String toString() { + return "Organization(" + homePage + positions + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Organization that = (Organization) o; + return Objects.equals(homePage, that.homePage) && + Objects.equals(positions, that.positions); + } + + @Override + public int hashCode() { + int result = homePage != null ? homePage.hashCode() : 0; + result = 31 * result + (positions != null ? positions.hashCode() : 0); + return result; + } + + public Link getHomePage() { + return homePage; + } + + public List getPositions() { + return positions; + } + + @XmlAccessorType(XmlAccessType.FIELD) + public static class Position implements Serializable { + @XmlJavaTypeAdapter(LocalDateAdapter.class) + private LocalDate startDate; + @XmlJavaTypeAdapter(LocalDateAdapter.class) + private LocalDate endDate; + private String title; + private String description; + + public Position(int startYear, Month startMonth, String title, String description) { + this(DateUtil.of(startYear, startMonth), NOW, title, description); + } + + public Position(int startYear, Month startMonth, int endYear, Month endMonth, String title, String description) { + this(DateUtil.of(startYear, startMonth), DateUtil.of(endYear, endMonth), title, description); + } + + public Position() { + } + public Position(LocalDate startDate, LocalDate endDate, String title, String description) { + Objects.requireNonNull(startDate, "startDate must not be null"); + Objects.requireNonNull(endDate, "endDate must not be null"); + Objects.requireNonNull(title, "title must not be null"); + this.startDate = startDate; + this.endDate = endDate; + this.title = title; + this.description = description==null?"":description; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public void setEndDate(LocalDate endDate) { + this.endDate = endDate; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setDescription(String description) { + this.description = description; + } + + public LocalDate getStartDate() { + return startDate; + } + + public LocalDate getEndDate() { + return endDate; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Position position = (Position) o; + + if (!startDate.equals(position.startDate)) return false; + if (!endDate.equals(position.endDate)) return false; + if (!title.equals(position.title)) return false; + return description != null ? description.equals(position.description) : position.description == null; + } + + @Override + public int hashCode() { + int result = startDate.hashCode(); + result = 31 * result + endDate.hashCode(); + result = 31 * result + title.hashCode(); + result = 31 * result + (description != null ? description.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Position{" + + "startDate=" + startDate + + ", endDate=" + endDate + + ", title='" + title + '\'' + + ", description='" + description + '\'' + + '}'; + } + + } + +} diff --git a/src/com/urise/webapp/model/OrganizationSection.java b/src/com/urise/webapp/model/OrganizationSection.java new file mode 100644 index 00000000..7939021f --- /dev/null +++ b/src/com/urise/webapp/model/OrganizationSection.java @@ -0,0 +1,49 @@ +package com.urise.webapp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +@XmlAccessorType(XmlAccessType.FIELD) +public class OrganizationSection extends AbstractSection { + public static final long serialVersionUID = 1L; + private List organizations; + + public OrganizationSection() { + } + + public OrganizationSection(Organization... organizations) { + this(Arrays.asList(organizations)); + } + + public OrganizationSection(List organizations) { + Objects.requireNonNull(organizations, "organizations must not null"); + this.organizations = organizations; + } + + public List getOrganizations() { + return organizations; + } + + @Override + public String toString() { + return organizations.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + OrganizationSection that = (OrganizationSection) o; + + return organizations.equals(that.organizations); + } + + @Override + public int hashCode() { + return organizations.hashCode(); + } +} diff --git a/src/com/urise/webapp/model/Resume.java b/src/com/urise/webapp/model/Resume.java new file mode 100644 index 00000000..a01c02d4 --- /dev/null +++ b/src/com/urise/webapp/model/Resume.java @@ -0,0 +1,94 @@ +package com.urise.webapp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.EnumMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +/** + * Initial resume class + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class Resume implements Serializable { + public static final long serialVersionUID = 1L; + // Unique identifier + private String uuid; + private String fullName; + + private final Map contacts = new EnumMap<>(ContactType.class); + private final Map sections = new EnumMap<>(SectionType.class); + + public Resume() { + } + + public Resume(String fullName) { + this(UUID.randomUUID().toString(), fullName); + } + + public Resume(String uuid, String fullName) { + Objects.requireNonNull(fullName, "fullName must not be null"); + Objects.requireNonNull(uuid, "uuid must not be null"); + this.uuid = uuid.trim(); + this.fullName = fullName; + } + + + public String getContact(ContactType type) { + return contacts.get(type); + } + + public AbstractSection getSection(SectionType type) { + return sections.get(type); + } + + public void addSection(SectionType type, AbstractSection section) { + sections.put(type, section); + } + + public void addContact(ContactType type, String contact) { + contacts.put(type, contact); + } + + + public String getUuid() { + return uuid; + } + + public String getFullName() { + return fullName; + } + + public Map getContacts() { + return contacts; + } + + public Map getSections() { + return sections; + } + + @Override + public String toString() { + return uuid + "(" + fullName + ")"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Resume resume = (Resume) o; + return Objects.equals(uuid, resume.uuid) && + Objects.equals(fullName, resume.fullName) && + Objects.equals(contacts, resume.contacts) && + Objects.equals(sections, resume.sections); + } + + @Override + public int hashCode() { + return Objects.hash(uuid, fullName, contacts, sections); + } +} diff --git a/src/com/urise/webapp/model/SectionType.java b/src/com/urise/webapp/model/SectionType.java new file mode 100644 index 00000000..acf3e95b --- /dev/null +++ b/src/com/urise/webapp/model/SectionType.java @@ -0,0 +1,20 @@ +package com.urise.webapp.model; + +public enum SectionType { + PERSONAL("Личные качества"), + OBJECTIVE("Позиция"), + ACHIEVEMENT("Достижения"), + QUALIFICATIONS("Квалификация"), + EXPERIENCE("Опыт работы"), + EDUCATION("Образование"); + + private String title; + + SectionType(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } +} diff --git a/src/com/urise/webapp/model/TextSection.java b/src/com/urise/webapp/model/TextSection.java new file mode 100644 index 00000000..7ec97e1c --- /dev/null +++ b/src/com/urise/webapp/model/TextSection.java @@ -0,0 +1,43 @@ +package com.urise.webapp.model; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.util.Objects; + + +public class TextSection extends AbstractSection { + public static final long serialVersionUID = 1L; + private String content; + + public TextSection() { + } + + public TextSection(String content) { + Objects.requireNonNull(content, "content must not null"); + this.content = content; + } + + public String getContent() { + return content; + } + + @Override + public String toString() { + return content; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TextSection that = (TextSection) o; + + return content.equals(that.content); + } + + @Override + public int hashCode() { + return content.hashCode(); + } +} diff --git a/src/com/urise/webapp/sql/ABlockOfCode.java b/src/com/urise/webapp/sql/ABlockOfCode.java new file mode 100644 index 00000000..22e13212 --- /dev/null +++ b/src/com/urise/webapp/sql/ABlockOfCode.java @@ -0,0 +1,8 @@ +package com.urise.webapp.sql; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public interface ABlockOfCode { + T execute(PreparedStatement ps) throws SQLException; +} diff --git a/src/com/urise/webapp/sql/ConnectionFactory.java b/src/com/urise/webapp/sql/ConnectionFactory.java new file mode 100644 index 00000000..08dff921 --- /dev/null +++ b/src/com/urise/webapp/sql/ConnectionFactory.java @@ -0,0 +1,8 @@ +package com.urise.webapp.sql; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface ConnectionFactory { + Connection getConnection() throws SQLException; +} diff --git a/src/com/urise/webapp/sql/SqlHelper.java b/src/com/urise/webapp/sql/SqlHelper.java new file mode 100644 index 00000000..56ada966 --- /dev/null +++ b/src/com/urise/webapp/sql/SqlHelper.java @@ -0,0 +1,43 @@ +package com.urise.webapp.sql; + +import com.urise.webapp.exception.StorageException; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class SqlHelper { + private final ConnectionFactory connectionFactory; + + public SqlHelper(String dbUrl, String dbUser, String dbPassword) { + this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPassword); + } + + public T transactionalExecute(SqlTransaction executor) { + try (Connection conn = connectionFactory.getConnection()) { + try{ + conn.setAutoCommit(false);//после выпонения не будет выполняться автоматический commit + T res =executor.execute(conn); + conn.commit(); + return res; + } + catch (SQLException e){ + conn.rollback(); + throw e; + } + + } catch (SQLException e) { + throw new StorageException(e); + } + } + public T transactionExecute(ABlockOfCode aBlockOfCode, String sqlQuery) { + try (Connection conn = connectionFactory.getConnection(); + PreparedStatement ps = conn.prepareStatement(sqlQuery) + ) { + return aBlockOfCode.execute(ps); + } catch (SQLException e) { + throw new StorageException(e); + } + } +} diff --git a/src/com/urise/webapp/sql/SqlTransaction.java b/src/com/urise/webapp/sql/SqlTransaction.java new file mode 100644 index 00000000..cec601dd --- /dev/null +++ b/src/com/urise/webapp/sql/SqlTransaction.java @@ -0,0 +1,8 @@ +package com.urise.webapp.sql; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface SqlTransaction { + T execute (Connection conn) throws SQLException; +} diff --git a/src/com/urise/webapp/storage/AbstractArrayStorage.java b/src/com/urise/webapp/storage/AbstractArrayStorage.java new file mode 100644 index 00000000..881c7a24 --- /dev/null +++ b/src/com/urise/webapp/storage/AbstractArrayStorage.java @@ -0,0 +1,64 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; + +import java.util.Arrays; +import java.util.List; + +public abstract class AbstractArrayStorage extends AbstractStorage { + protected static final int MAX_SIZE = 10_000; + protected Resume[] storage = new Resume[MAX_SIZE]; + protected int resumeCounter = 0; + + @Override + public void clear() { + Arrays.fill(storage, 0, resumeCounter, null); + resumeCounter = 0; + } + + @Override + protected Resume doGet(Object index) { + return storage[(Integer) index]; + } + + @Override + public void doDelete(Object index) { + deleteResume((Integer) index); + storage[resumeCounter - 1] = null; + resumeCounter--; + } + + @Override + protected void doUpdate(Resume resume, Object index) { + storage[(Integer) index] = resume; + } + + @Override + protected void doSave(Resume resume, Object index) { + if (resumeCounter >= MAX_SIZE) { + throw new StorageException("Storage overflow", resume.getUuid()); + } + insertResume(resume, (Integer) index); + resumeCounter++; + } + + @Override + protected List doCopyAll() { + return Arrays.asList(Arrays.copyOfRange(storage, 0, resumeCounter)); + } + + @Override + public int size() { + return resumeCounter; + } + + @Override + protected boolean isExist(Object index) { + return (Integer) index >= 0; + } + + protected abstract void insertResume(Resume resume, int index); + + protected abstract void deleteResume(int index); +} diff --git a/src/com/urise/webapp/storage/AbstractStorage.java b/src/com/urise/webapp/storage/AbstractStorage.java new file mode 100644 index 00000000..7321c560 --- /dev/null +++ b/src/com/urise/webapp/storage/AbstractStorage.java @@ -0,0 +1,68 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.ExistStorageException; +import com.urise.webapp.exception.NotExistStorageException; +import com.urise.webapp.model.Resume; + +import java.util.Comparator; +import java.util.List; + + +public abstract class AbstractStorage implements Storage { + protected final Comparator RESUME_COMPARATOR_FULLNAME = Comparator.comparing(Resume::getFullName).thenComparing(Resume::getUuid); + + protected abstract void doUpdate(Resume resume, Object searchKey); + + protected abstract boolean isExist(Object searchKey); + + protected abstract void doSave(Resume resume, Object searchKey); + + protected abstract Resume doGet(Object searchKey); + + protected abstract void doDelete(Object searchKey); + + protected abstract Object getSearchKey(String uuid); + + protected abstract List doCopyAll(); + + public List getAllSorted() { + List resumes = doCopyAll(); + resumes.sort(RESUME_COMPARATOR_FULLNAME); + return resumes; + } + + + public void save(Resume resume) { + doSave(resume, getNotExistedSearchKey(resume.getUuid())); + } + + public void delete(String uuid) { + doDelete(getExistedSearchKey(uuid)); + } + + public void update(Resume resume) { + doUpdate(resume, getExistedSearchKey(resume.getUuid())); + } + + public Resume get(String uuid) { + return doGet(getExistedSearchKey(uuid)); + } + + + private Object getExistedSearchKey(String uuid) { + Object searchKey = getSearchKey(uuid); + if (!isExist(searchKey)) { + throw new NotExistStorageException(uuid); + } + return searchKey; + } + + private Object getNotExistedSearchKey(String uuid) { + Object searchKey = getSearchKey(uuid); + if (isExist(searchKey)) { + throw new ExistStorageException(uuid); + } + return searchKey; + } + +} diff --git a/src/com/urise/webapp/storage/ArrayStorage.java b/src/com/urise/webapp/storage/ArrayStorage.java new file mode 100644 index 00000000..795c89cb --- /dev/null +++ b/src/com/urise/webapp/storage/ArrayStorage.java @@ -0,0 +1,32 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.Resume; + + +/** + * Array based mapStorage for Resumes + */ +public class ArrayStorage extends AbstractArrayStorage { + + @Override + protected Integer getSearchKey(String uuid) { + for (int i = 0; i < resumeCounter; i++) { + if (storage[i].getUuid().equals(uuid)) { + return i; + } + } + return -1; + } + + + @Override + protected void insertResume(Resume resume, int index) { + storage[resumeCounter] = resume; + } + + @Override + protected void deleteResume(int index) { + storage[index] = storage[resumeCounter - 1]; + } + +} diff --git a/src/com/urise/webapp/storage/FileStorage.java b/src/com/urise/webapp/storage/FileStorage.java new file mode 100644 index 00000000..eddc84e0 --- /dev/null +++ b/src/com/urise/webapp/storage/FileStorage.java @@ -0,0 +1,110 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; +import com.urise.webapp.storage.serializer.StreamSerializer; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class FileStorage extends AbstractStorage { + private File directory; + private StreamSerializer streamSerializer; + + protected FileStorage(File directory, StreamSerializer streamSerializer) { + Objects.requireNonNull(directory, "directory must not null"); + this.streamSerializer = streamSerializer; + if (!directory.isDirectory()) { + throw new IllegalArgumentException(directory.getAbsolutePath() + " is not directory"); + } + if (!directory.canRead() || !directory.canWrite()) { + throw new IllegalArgumentException(directory.getAbsolutePath() + " is not readable/writable"); + } + this.directory = directory; + } + + + @Override + protected void doUpdate(Resume resume, Object searchKey) { + File file = (File) searchKey; + try { + streamSerializer.doWrite(resume, new BufferedOutputStream(new FileOutputStream(file))); + } catch (IOException e) { + throw new StorageException("File write error", resume.getUuid(), e); + } + } + + @Override + protected boolean isExist(Object file) { + return ((File) file).exists(); + } + + @Override + protected void doSave(Resume resume, Object file) { + File f = ((File) file); + try { + + f.createNewFile(); + } catch (IOException e) { + throw new StorageException("Couldn't create file " + f.getAbsolutePath(), f.getName(), e); + } + doUpdate(resume, f); + } + + @Override + protected Resume doGet(Object searchKey) { + File file = (File) searchKey; + try { + return streamSerializer.doRead(new BufferedInputStream(new FileInputStream(file))); + } catch (IOException e) { + throw new StorageException("File read error", file.getName(), e); + } + } + + @Override + protected void doDelete(Object searchKey) { + File f = (File) searchKey; + f.delete(); +//удаляет файл + } + + @Override + protected File getSearchKey(String uuid) { + return new File(directory, uuid); + } + + @Override + protected List doCopyAll() { + //читает все файлы и делает do Read и возвращает list + List resumes = new ArrayList<>(); + File[] files = directory.listFiles(); + if (files == null) { + return resumes; + } + for (File f : files) { + resumes.add(doGet(f)); + } + return resumes; + } + + @Override + public void clear() { + //получить все файлыиз каталога и удалить + File[] files = directory.listFiles(); + if (files == null) { + return; + } + for (File f : files) { + f.delete(); + } + } + + @Override + public int size() { + //количество фалов в каталоге + File[] files = directory.listFiles(); + return files == null ? 0 : files.length; + } +} diff --git a/src/com/urise/webapp/storage/ListStorage.java b/src/com/urise/webapp/storage/ListStorage.java new file mode 100644 index 00000000..928bf220 --- /dev/null +++ b/src/com/urise/webapp/storage/ListStorage.java @@ -0,0 +1,60 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.Resume; + +import java.util.ArrayList; +import java.util.List; + +public class ListStorage extends AbstractStorage { + private List list = new ArrayList<>(); + + @Override + protected void doUpdate(Resume resume, Object searchKey) { + list.set((Integer) searchKey, resume); + } + + @Override + protected boolean isExist(Object searchKey) { + return searchKey != null; + } + + @Override + protected void doSave(Resume resume, Object searchKey) { + list.add(resume); + } + + @Override + protected Resume doGet(Object searchKey) { + return list.get((Integer) searchKey); + } + + @Override + protected void doDelete(Object searchKey) { + list.remove(((Integer) searchKey).intValue()); + } + + @Override + protected Integer getSearchKey(String uuid) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i).getUuid().equals(uuid)) { + return i; + } + } + return null; + } + + @Override + public void clear() { + list.clear(); + } + + @Override + protected List doCopyAll() { + return new ArrayList<>(list); + } + + @Override + public int size() { + return list.size(); + } +} diff --git a/src/com/urise/webapp/storage/MapResumeStorage.java b/src/com/urise/webapp/storage/MapResumeStorage.java new file mode 100644 index 00000000..c62c4c4f --- /dev/null +++ b/src/com/urise/webapp/storage/MapResumeStorage.java @@ -0,0 +1,57 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.Resume; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MapResumeStorage extends AbstractStorage { + private Map mapStorage = new HashMap<>(); + + @Override + protected void doUpdate(Resume resume, Object searchKey) { + mapStorage.put(((Resume) searchKey).getUuid(), resume); + } + + @Override + protected boolean isExist(Object searchKey) { + return searchKey != null; + } + + @Override + protected void doSave(Resume resume, Object searchKey) { + mapStorage.put(resume.getUuid(), resume); + } + + @Override + protected Resume doGet(Object searchKey) { + return (Resume) searchKey; + } + + @Override + protected void doDelete(Object searchKey) { + mapStorage.remove(((Resume) searchKey).getUuid()); + } + + @Override + protected Resume getSearchKey(String uuid) { + return mapStorage.get(uuid); + } + + @Override + protected List doCopyAll() { + return new ArrayList<>(mapStorage.values()); + } + + @Override + public void clear() { + mapStorage.clear(); + } + + @Override + public int size() { + return mapStorage.size(); + } +} diff --git a/src/com/urise/webapp/storage/MapStorage.java b/src/com/urise/webapp/storage/MapStorage.java new file mode 100644 index 00000000..a4ca7880 --- /dev/null +++ b/src/com/urise/webapp/storage/MapStorage.java @@ -0,0 +1,58 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.Resume; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class MapStorage extends AbstractStorage { + private Map mapStorage = new HashMap<>(); + + @Override + protected void doUpdate(Resume resume, Object searchKey) { + mapStorage.put((String) searchKey, resume); + } + + @Override + protected boolean isExist(Object searchKey) { + return mapStorage.containsKey(searchKey); + } + + @Override + protected void doSave(Resume resume, Object searchKey) { + mapStorage.put((String) searchKey, resume); + } + + @Override + protected Resume doGet(Object searchKey) { + return mapStorage.get(searchKey); + } + + @Override + protected void doDelete(Object searchKey) { + mapStorage.remove(searchKey); + } + + @Override + protected String getSearchKey(String uuid) { + return uuid; + } + + @Override + public void clear() { + mapStorage.clear(); + } + + @Override + protected List doCopyAll() { + return new ArrayList<>(mapStorage.values()); + } + + @Override + public int size() { + return mapStorage.size(); + } +} diff --git a/src/com/urise/webapp/storage/PathStorage.java b/src/com/urise/webapp/storage/PathStorage.java new file mode 100644 index 00000000..e33d9d64 --- /dev/null +++ b/src/com/urise/webapp/storage/PathStorage.java @@ -0,0 +1,112 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; +import com.urise.webapp.storage.serializer.StreamSerializer; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class PathStorage extends AbstractStorage { + private Path directory; + private StreamSerializer streamSerializer; + + protected PathStorage(String dir, StreamSerializer streamSerializer) { + Path directory = Paths.get(dir); + Objects.requireNonNull(directory, "directory must not null"); + this.streamSerializer = streamSerializer; + if (!Files.isDirectory(directory) || !Files.isWritable(directory)) { + throw new IllegalArgumentException(dir + " is not directory or is not writable"); + } + this.directory = directory; + } + + @Override + protected void doUpdate(Resume resume, Object searchKey) { + Path file = (Path) searchKey; + try { + streamSerializer.doWrite(resume, new BufferedOutputStream(new FileOutputStream(file.toString()))); + } catch (IOException e) { + throw new StorageException("File write error", resume.getUuid(), e); + } + } + + @Override + protected boolean isExist(Object file) { + Path path = (Path) file; + return Files.isRegularFile(path); + } + + @Override + protected void doSave(Resume resume, Object file) { + Path path = ((Path) file); + try { + Files.createFile(path); + } catch (IOException e) { + throw new StorageException("Couldn't create file " + path.toString(), path.getFileName().toString(), e); + } + doUpdate(resume, path); + } + + @Override + protected Resume doGet(Object searchKey) { + Path path = (Path) searchKey; + try { + return streamSerializer.doRead(new BufferedInputStream(new FileInputStream(path.toString()))); + } catch (IOException e) { + throw new StorageException("File read error", path.toString(), e); + } + } + + @Override + protected void doDelete(Object searchKey) { + Path path = (Path) searchKey; + try { + Files.delete(path); + } catch (IOException e) { + throw new StorageException("File deleting error " + path.toString(), path.toString(), e); + } +//удаляет файл + } + + @Override + protected Path getSearchKey(String uuid) { + return directory.resolve(uuid); + } + + @Override + protected List doCopyAll() { + //читает все файлы и делает doRead и возвращает list + List resumes; + try { + resumes = Files.list(directory).map(this::doGet).collect(Collectors.toList()); + } catch (IOException e) { + throw new StorageException("Files read error", null, e); + } + return resumes; + } + + @Override + public void clear() { + try { + Files.list(directory).forEach(this::doDelete); + } catch (IOException e) { + throw new StorageException("File delete error", null, e); + } + } + + @Override + public int size() { + //количество фалов в каталоге + try { + return (int) Files.list(directory).count(); + } catch (IOException e) { + throw new StorageException("Directory file read error", null, e); + } + } +} diff --git a/src/com/urise/webapp/storage/SortedArrayStorage.java b/src/com/urise/webapp/storage/SortedArrayStorage.java new file mode 100644 index 00000000..b58ed789 --- /dev/null +++ b/src/com/urise/webapp/storage/SortedArrayStorage.java @@ -0,0 +1,30 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.Resume; + +import java.util.Arrays; +import java.util.Comparator; + +public class SortedArrayStorage extends AbstractArrayStorage { + + protected final Comparator RESUME_COMPARATOR_UUID = Comparator.comparing(Resume::getUuid); + + @Override + protected Integer getSearchKey(String uuid) { + Resume resume = new Resume(uuid, "defaultFullName"); + return Arrays.binarySearch(storage, 0, resumeCounter, resume, RESUME_COMPARATOR_UUID); + } + + @Override + protected void insertResume(Resume resume, int index) { + int indexResume = -index - 1; + System.arraycopy(storage, indexResume, storage, indexResume + 1, resumeCounter - indexResume); + storage[indexResume] = resume; + } + + @Override + protected void deleteResume(int index) { + System.arraycopy(storage, index + 1, storage, index, resumeCounter - index - 1); + } + +} diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java new file mode 100644 index 00000000..58bdb4b7 --- /dev/null +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -0,0 +1,120 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.NotExistStorageException; +import com.urise.webapp.model.ContactType; +import com.urise.webapp.model.Resume; +import com.urise.webapp.sql.SqlHelper; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class SqlStorage implements Storage { + public final SqlHelper sqlHelper; + + public SqlStorage(String dbUrl, String dbUser, String dbPassword) { + sqlHelper = new SqlHelper(dbUrl, dbUser, dbPassword); + } + + @Override + public void clear() { + sqlHelper.transactionExecute(ps -> ps.execute(), "DELETE FROM RESUME"); + } + + @Override + public void save(Resume resume) { + sqlHelper.transactionalExecute(conn -> { + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO RESUME (uuid, full_name) values (?,?)")) { + ps.setString(1, resume.getUuid()); + ps.setString(2, resume.getFullName()); + ps.execute(); + } + + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO contact (resume_uuid, type, value) values (?,?,?)")) { + for (Map.Entry entry : resume.getContacts().entrySet()) { + ps.setString(1, resume.getUuid()); + ps.setString(2, entry.getKey().name()); + ps.setString(3, entry.getValue()); + ps.addBatch(); + } + ps.executeBatch(); + } + return null; + } + ); + } + + + @Override + public Resume get(String uuid) { + return sqlHelper.transactionExecute(ps -> { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + Resume r = new Resume(uuid, rs.getString("full_name")); + do { + String value = rs.getString("value"); + ContactType type = ContactType.valueOf(rs.getString("type")); + r.addContact(type, value); + } while (rs.next()); + return r; + }, + "SELECT * FROM RESUME r " + + "LEFT JOIN CONTACT c on (r.uuid=c.resume_uuid) " + + "WHERE r.uuid=?"); + } + + @Override + public void delete(String uuid) { + /*удаление по каскаду*/ + sqlHelper.transactionExecute(p -> { + p.setString(1, uuid); + if (p.executeUpdate() == 0) { + throw new NotExistStorageException(uuid); + } + return null; + }, "DELETE from RESUME where UUID=?"); + } + + @Override + public List getAllSorted() { + return sqlHelper.transactionExecute(p -> { + ResultSet rs = p.executeQuery(); + List list = new ArrayList<>(); + while (rs.next()) { + list.add(new Resume(rs.getString("uuid"), rs.getString("full_name"))); + } + return list; + }, "SELECT * FROM RESUME ORDER BY full_name,uuid"); + + } + + @Override + public int size() { + return sqlHelper.transactionExecute(ps -> { + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + return 0; + } + return rs.getInt(1); + }, "SELECT count (uuid) FROM RESUME"); + } + + @Override + public void update(Resume resume) { + sqlHelper.transactionExecute(ps -> { + ps.setString(1, resume.getFullName()); + ps.setString(2, resume.getUuid()); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(resume.getUuid()); + } + return null; + }, "UPDATE RESUME set full_name=? where uuid=?"); + } + + +} diff --git a/src/com/urise/webapp/storage/Storage.java b/src/com/urise/webapp/storage/Storage.java new file mode 100644 index 00000000..c31e45fd --- /dev/null +++ b/src/com/urise/webapp/storage/Storage.java @@ -0,0 +1,25 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.Resume; + +import java.util.List; + +/** + * Array based mapStorage for Resumes + */ +public interface Storage { + + void clear(); + + void save(Resume resume); + + Resume get(String uuid); + + void delete(String uuid); + + List getAllSorted(); + + int size(); + + void update(Resume resume); +} diff --git a/src/com/urise/webapp/storage/serializer/DataStreamSerializer.java b/src/com/urise/webapp/storage/serializer/DataStreamSerializer.java new file mode 100644 index 00000000..77fcad83 --- /dev/null +++ b/src/com/urise/webapp/storage/serializer/DataStreamSerializer.java @@ -0,0 +1,137 @@ +package com.urise.webapp.storage.serializer; + +import com.urise.webapp.model.*; + +import java.io.*; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class DataStreamSerializer implements StreamSerializer { + + @Override + public void doWrite(Resume r, OutputStream os) throws IOException { + try (DataOutputStream dos = new DataOutputStream(os)) { + dos.writeUTF(r.getUuid()); + dos.writeUTF(r.getFullName()); + Map contacts = r.getContacts(); + writeCollection(dos, contacts.entrySet(), entry -> { + dos.writeUTF(entry.getKey().name()); + dos.writeUTF(entry.getValue()); + }); + + writeCollection(dos, r.getSections().entrySet(), entry -> { + SectionType type = entry.getKey(); + AbstractSection section = entry.getValue(); + dos.writeUTF(type.name()); + switch (type) { + case PERSONAL: + case OBJECTIVE: + dos.writeUTF(((TextSection) section).getContent()); + break; + case ACHIEVEMENT: + case QUALIFICATIONS: + writeCollection(dos, ((ListSection) section).getItems(), dos::writeUTF); + break; + case EXPERIENCE: + case EDUCATION: + writeCollection(dos, ((OrganizationSection) section).getOrganizations(), org -> { + dos.writeUTF(org.getHomePage().getName()); + dos.writeUTF(org.getHomePage().getUrl()); + writeCollection(dos, org.getPositions(), position -> { + writeLocalDate(dos, position.getStartDate()); + writeLocalDate(dos, position.getEndDate()); + dos.writeUTF(position.getTitle()); + dos.writeUTF(position.getDescription()); + }); + }); + break; + } + }); + } + } + + private void writeLocalDate(DataOutputStream dos, LocalDate ld) throws IOException { + dos.writeInt(ld.getYear()); + dos.writeInt(ld.getMonth().getValue()); + dos.writeInt(ld.getDayOfMonth()); + } + + private LocalDate readLocalDate(DataInputStream dis) throws IOException { + return LocalDate.of(dis.readInt(), dis.readInt(), dis.readInt()); + } + + @Override + public Resume doRead(InputStream is) throws IOException { + try (DataInputStream dis = new DataInputStream(is)) { + String uuid = dis.readUTF(); + String fullName = dis.readUTF(); + Resume resume = new Resume(uuid, fullName); + readItems(dis, () -> resume.addContact(ContactType.valueOf(dis.readUTF()), dis.readUTF())); + readItems(dis, () -> { + SectionType sectionType = SectionType.valueOf(dis.readUTF()); + resume.addSection(sectionType, readSection(dis, sectionType)); + }); + return resume; + } + } + + private AbstractSection readSection(DataInputStream dis, SectionType sectionType) throws IOException { + switch (sectionType) { + case PERSONAL: + case OBJECTIVE: + return new TextSection(dis.readUTF()); + case ACHIEVEMENT: + case QUALIFICATIONS: + return new ListSection(readList(dis, dis::readUTF)); + case EXPERIENCE: + case EDUCATION: + return new OrganizationSection( + readList(dis, () -> new Organization( + new Link(dis.readUTF(), dis.readUTF()), + readList(dis, () -> new Organization.Position( + readLocalDate(dis), readLocalDate(dis), dis.readUTF(), dis.readUTF() + )) + ))); + default: + throw new IllegalStateException(); + } + } + + private List readList(DataInputStream dis, ElementReader reader) throws IOException { + int size = dis.readInt(); + List list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(reader.read()); + } + return list; + } + + private interface ElementProcessor { + void process() throws IOException; + } + + private interface ElementReader { + T read() throws IOException; + } + + private interface ElementWriter { + void write(T t) throws IOException; + } + + private void readItems(DataInputStream dis, ElementProcessor processor) throws IOException { + int size = dis.readInt(); + for (int i = 0; i < size; i++) { + processor.process(); + } + } + + private void writeCollection(DataOutputStream dos, Collection collection, ElementWriter writer) throws IOException { + dos.writeInt(collection.size()); + for (T item : collection) { + writer.write(item); + } + } +} \ No newline at end of file diff --git a/src/com/urise/webapp/storage/serializer/JsonStreamSerializer.java b/src/com/urise/webapp/storage/serializer/JsonStreamSerializer.java new file mode 100644 index 00000000..5c4a9316 --- /dev/null +++ b/src/com/urise/webapp/storage/serializer/JsonStreamSerializer.java @@ -0,0 +1,27 @@ +package com.urise.webapp.storage.serializer; + +import com.urise.webapp.model.*; +import com.urise.webapp.util.JsonParser; +import com.urise.webapp.util.XmlParser; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +public class JsonStreamSerializer implements StreamSerializer { + + + @Override + public void doWrite(Resume r, OutputStream os) throws IOException { + try (Writer w = new OutputStreamWriter(os, StandardCharsets.UTF_8)) { + JsonParser.write(r,w); + } + } + + @Override + public Resume doRead(InputStream is) throws IOException { + try (Reader r = new InputStreamReader(is, StandardCharsets.UTF_8)) { + return JsonParser.read(r, Resume.class); + } + + } +} diff --git a/src/com/urise/webapp/storage/serializer/ObjectStreamSerializer.java b/src/com/urise/webapp/storage/serializer/ObjectStreamSerializer.java new file mode 100644 index 00000000..7434a062 --- /dev/null +++ b/src/com/urise/webapp/storage/serializer/ObjectStreamSerializer.java @@ -0,0 +1,25 @@ +package com.urise.webapp.storage.serializer; + +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; + +import java.io.*; + +public class ObjectStreamSerializer implements StreamSerializer { + + @Override + public void doWrite(Resume resume, OutputStream os) throws IOException { + try (ObjectOutputStream oos = new ObjectOutputStream(os)) { + oos.writeObject(resume); + } + } + + @Override + public Resume doRead(InputStream is) throws IOException { + try (ObjectInputStream ois = new ObjectInputStream(is)) { + return (Resume) ois.readObject(); + } catch (ClassNotFoundException e) { + throw new StorageException("Error read resume", null, e); + } + } +} diff --git a/src/com/urise/webapp/storage/serializer/StreamSerializer.java b/src/com/urise/webapp/storage/serializer/StreamSerializer.java new file mode 100644 index 00000000..a7e7eaeb --- /dev/null +++ b/src/com/urise/webapp/storage/serializer/StreamSerializer.java @@ -0,0 +1,13 @@ +package com.urise.webapp.storage.serializer; + +import com.urise.webapp.model.Resume; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public interface StreamSerializer { + void doWrite(Resume r, OutputStream os) throws IOException; + + Resume doRead(InputStream is) throws IOException; +} diff --git a/src/com/urise/webapp/storage/serializer/XmlStreamSerializer.java b/src/com/urise/webapp/storage/serializer/XmlStreamSerializer.java new file mode 100644 index 00000000..05013cab --- /dev/null +++ b/src/com/urise/webapp/storage/serializer/XmlStreamSerializer.java @@ -0,0 +1,32 @@ +package com.urise.webapp.storage.serializer; + +import com.urise.webapp.model.*; +import com.urise.webapp.util.XmlParser; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +public class XmlStreamSerializer implements StreamSerializer { + private XmlParser xmlParser; + + public XmlStreamSerializer() { + this.xmlParser = new XmlParser(Resume.class, Organization.class, Link.class, + OrganizationSection.class, TextSection.class, ListSection.class, + Organization.Position.class); + } + + @Override + public void doWrite(Resume r, OutputStream os) throws IOException { + try (Writer w = new OutputStreamWriter(os, StandardCharsets.UTF_8)) { + xmlParser.marshall(r, w); + } + } + + @Override + public Resume doRead(InputStream is) throws IOException { + try (Reader r = new InputStreamReader(is, StandardCharsets.UTF_8)) { + return xmlParser.unmarshall(r); + } + + } +} diff --git a/src/com/urise/webapp/util/DateUtil.java b/src/com/urise/webapp/util/DateUtil.java new file mode 100644 index 00000000..ec6ca4a7 --- /dev/null +++ b/src/com/urise/webapp/util/DateUtil.java @@ -0,0 +1,12 @@ +package com.urise.webapp.util; + +import java.time.LocalDate; +import java.time.Month; + +public class DateUtil { + public static final LocalDate NOW = LocalDate.of(3000, 1, 1); + + public static LocalDate of(int year, Month month) { + return LocalDate.of(year, month, 1); + } +} diff --git a/src/com/urise/webapp/util/JsonParser.java b/src/com/urise/webapp/util/JsonParser.java new file mode 100644 index 00000000..63f2537e --- /dev/null +++ b/src/com/urise/webapp/util/JsonParser.java @@ -0,0 +1,22 @@ +package com.urise.webapp.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.urise.webapp.model.AbstractSection; + +import java.io.Reader; +import java.io.Writer; + +public class JsonParser { + private static Gson GSON = new GsonBuilder() + .registerTypeAdapter(AbstractSection.class, new JsonSectionAdapter()) + .create(); + + public static T read(Reader reader, Class clazz) { + return GSON.fromJson(reader, clazz); + } + + public static void write(T object, Writer writer) { + GSON.toJson(object, writer); + } +} diff --git a/src/com/urise/webapp/util/JsonSectionAdapter.java b/src/com/urise/webapp/util/JsonSectionAdapter.java new file mode 100644 index 00000000..93ef3de0 --- /dev/null +++ b/src/com/urise/webapp/util/JsonSectionAdapter.java @@ -0,0 +1,36 @@ +package com.urise.webapp.util; + +import com.google.gson.*; + +import java.lang.reflect.Type; + +public class JsonSectionAdapter implements JsonSerializer, JsonDeserializer { + private static final String CLASSNAME = "CLASSNAME"; + private static final String INSTANCE = "INSTANCE"; + + @Override + public T deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + //считываем свойство CLASSNAME - имя класса + JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME); + String className = prim.getAsString(); + try{ + Class clazz = Class.forName(className); + return context.deserialize(jsonObject.get(INSTANCE),clazz); + } catch (ClassNotFoundException e) { + throw new JsonParseException(e.getMessage()); + } + } + + @Override + public JsonElement serialize(T section, Type type, JsonSerializationContext context) { + JsonObject retValue =new JsonObject(); + //добавляем свойство classname + retValue.addProperty(CLASSNAME, section.getClass().getName()); + //сериализуем инстанс + JsonElement elem =context.serialize(section); + //добавляем инстанс + retValue.add(INSTANCE,elem); + return retValue; + } +} diff --git a/src/com/urise/webapp/util/LocalDateAdapter.java b/src/com/urise/webapp/util/LocalDateAdapter.java new file mode 100644 index 00000000..0a23fcf9 --- /dev/null +++ b/src/com/urise/webapp/util/LocalDateAdapter.java @@ -0,0 +1,16 @@ +package com.urise.webapp.util; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.time.LocalDate; + +public class LocalDateAdapter extends XmlAdapter { + + public LocalDate unmarshal(String v) throws Exception { + return LocalDate.parse(v); + } + + public String marshal(LocalDate v) throws Exception { + return v.toString(); + } + +} \ No newline at end of file diff --git a/src/com/urise/webapp/util/XmlParser.java b/src/com/urise/webapp/util/XmlParser.java new file mode 100644 index 00000000..322678b3 --- /dev/null +++ b/src/com/urise/webapp/util/XmlParser.java @@ -0,0 +1,37 @@ +package com.urise.webapp.util; + +import javax.xml.bind.*; +import java.io.Reader; +import java.io.Writer; + +public class XmlParser { + private final Marshaller marshaller; + private final Unmarshaller unmarshaller; + + public XmlParser (Class... classesToBeBound){ + try{ + JAXBContext ctx=JAXBContext.newInstance(classesToBeBound); + marshaller=ctx.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true); + marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8"); + unmarshaller=ctx.createUnmarshaller(); + } catch (JAXBException e) { + throw new IllegalStateException(e); + } + } + + public T unmarshall (Reader reader){ + try{ + return (T) unmarshaller.unmarshal(reader); + } catch (JAXBException e) { + throw new IllegalStateException(e); + } + } + public void marshall (Object instance, Writer writer){ + try{ + marshaller.marshal(instance, writer); + } catch (JAXBException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/src/com/urise/webapp/util/minValue.java b/src/com/urise/webapp/util/minValue.java new file mode 100644 index 00000000..9fadf3dd --- /dev/null +++ b/src/com/urise/webapp/util/minValue.java @@ -0,0 +1,64 @@ +package com.urise.webapp.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class minValue { + public static void main(String[] args) { + List values = new ArrayList<>(); + for (int i = 1; i < 10; i++) { + values.add((int) (Math.random() * 10)); + } + printStream(values.stream(), "Source data"); + System.out.println("Sum of elements =" + values.stream().reduce((x1, x2) -> x1 + x2).get()); + System.out.println("Min number = " + minValue(values.toArray(new Integer[9]))); + printStream(oddOrEven(values).stream(), "List without streams"); + printStream(oddOrEvenOptional(values).stream(), "List created using stream line!"); + + } + + private static void printStream(Stream stream, String title) { + System.out.println("------" + title + "------"); + stream.forEach(System.out::println); + System.out.println("-------------------------"); + } + + public static int minValue(Integer[] values) { + + return Arrays.stream(values) + .distinct() + .sorted() + .reduce((z, y) -> z*10 + y).orElse(0); + + } + + static List oddOrEven(List integers) { + List evenList = new ArrayList<>(); + List oddList = new ArrayList<>(); + int sum = 0; + for (int i = 0; i < integers.size(); i++) { + int elem = integers.get(i); + sum = +elem; + if (elem % 2 == 0) { + oddList.add(elem); + } else { + evenList.add(elem); + } + } + return sum % 2 == 0 ? oddList : evenList; + } + + static List oddOrEvenOptional(List integers) { + return integers.stream() + .collect(Collectors.partitioningBy((x) -> x % 2 == 0)) + .get(integers.stream() + .reduce(0, (x1, x2) -> x1 += x2) % 2 != 0); + } + +} diff --git a/test/com/urise/webapp/storage/AbstractArrayStorageTest.java b/test/com/urise/webapp/storage/AbstractArrayStorageTest.java new file mode 100644 index 00000000..e7074929 --- /dev/null +++ b/test/com/urise/webapp/storage/AbstractArrayStorageTest.java @@ -0,0 +1,28 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; +import org.junit.Test; + +import static com.urise.webapp.storage.AbstractArrayStorage.MAX_SIZE; +import static org.junit.Assert.fail; + +public abstract class AbstractArrayStorageTest extends AbstractStorageTest { + + public AbstractArrayStorageTest(AbstractArrayStorage storage) { + super(storage); + } + + @Test(expected = StorageException.class) + public void sizeOverLoaded() { + try { + + for (int i = 4; i <= MAX_SIZE; i++) { + storage.save(new Resume("FIO_" + i)); + } + } catch (StorageException e) { + fail(e.getMessage()); + } + storage.save(new Resume("FIO_" + MAX_SIZE + 1)); + } +} diff --git a/test/com/urise/webapp/storage/AbstractStorageTest.java b/test/com/urise/webapp/storage/AbstractStorageTest.java new file mode 100644 index 00000000..a4c27c5b --- /dev/null +++ b/test/com/urise/webapp/storage/AbstractStorageTest.java @@ -0,0 +1,119 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.Config; +import com.urise.webapp.exception.ExistStorageException; +import com.urise.webapp.exception.NotExistStorageException; +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; + +public abstract class AbstractStorageTest { + protected static final File STORAGE_DIR = Config.getInstance().getStorageDir(); + private static final String UUID_1 = "UUID_1"; + private static final String UUID_2 = "UUID_2"; + private static final String UUID_3 = "UUID_3"; + private static final String UUID_4 = "UUID_4"; + private static final Resume R_1 = new Resume(UUID_1, "FullName_1"); + private static final Resume R_2 = new Resume(UUID_2, "FullName_2"); + private static final Resume R_3 = new Resume(UUID_3, "FullName_3"); + private static final Resume R_4 = new Resume(UUID_4, "FullName_4"); + + static { + /* ResumeDataTest.fillResumeSections(R_1, 3, 3, 3, 3); + ResumeDataTest.fillResumeSections(R_2, 4, 4, 4, 4); + ResumeDataTest.fillResumeSections(R_3, 5, 5, 5, 5); + ResumeDataTest.fillResumeSections(R_4, 6, 6, 6, 6); + */} + + protected Storage storage; + + protected AbstractStorageTest(Storage storage) { + this.storage = storage; + } + + @Before + public void setUp() { + storage.clear(); + + storage.save(R_1); + storage.save(R_2); + storage.save(R_3); + } + + @Test + public void clear() { + storage.clear(); + assertEquals(0, storage.size()); + } + + @Test(expected = ExistStorageException.class) + public void saveExist() { + storage.save(R_3); + } + + @Test + public void saveNotExist() { + int sizeBefore = storage.size(); + storage.save(R_4); + assertEquals(sizeBefore + 1, storage.size()); + assertEquals(R_4, storage.get(UUID_4)); + } + + @Test + public void getExist() { + R_1.equals(storage.get(UUID_1)); + assertEquals(R_1, storage.get(UUID_1)); + assertEquals(R_2, storage.get(UUID_2)); + assertEquals(R_3, storage.get(UUID_3)); + } + + @Test(expected = NotExistStorageException.class) + public void getNotExist() { + storage.get("notExistableUUID"); + } + + @Test(expected = NotExistStorageException.class) + public void deleteExist() { + int sizeBefore = storage.size(); + storage.delete(UUID_1); + assertEquals(sizeBefore - 1, storage.size()); + storage.get(UUID_1); + + } + + @Test(expected = NotExistStorageException.class) + public void deleteNotExist() { + storage.delete("notExistableUUID"); + } + + @Test + public void getAllSorted() { + assertEquals(Arrays.asList(R_1, R_2, R_3), storage.getAllSorted()); + } + + @Test + public void size() { + assertEquals(3, storage.size()); + } + + @Test + public void updateExist() { + Resume rBefore = storage.get(UUID_1); + Resume rAfter = new Resume(UUID_1, "FullName_1"); + storage.update(rAfter); + assertNotSame(storage.get(UUID_1), rBefore); + } + + @Test(expected = NotExistStorageException.class) + public void updateNotExist() { + Resume rAfter = new Resume("test"); + storage.update(rAfter); + } +} \ No newline at end of file diff --git a/test/com/urise/webapp/storage/AllStorageTest.java b/test/com/urise/webapp/storage/AllStorageTest.java new file mode 100644 index 00000000..11c17fa8 --- /dev/null +++ b/test/com/urise/webapp/storage/AllStorageTest.java @@ -0,0 +1,21 @@ +package com.urise.webapp.storage; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + ArrayStorageTest.class, + SortedArrayStorageTest.class, + ListStorageTest.class, + MapStorageTest.class, + MapResumeStorageTest.class, + ObjectFileStorageTest.class, + ObjectPathStorageTest.class, + XmlPathStorageTest.class, + JsonPathStorageTest.class, + DataPathStorageTest.class, + SqlStorageTest.class +}) +public class AllStorageTest { +} diff --git a/test/com/urise/webapp/storage/ArrayStorageTest.java b/test/com/urise/webapp/storage/ArrayStorageTest.java new file mode 100644 index 00000000..9a2c364b --- /dev/null +++ b/test/com/urise/webapp/storage/ArrayStorageTest.java @@ -0,0 +1,8 @@ +package com.urise.webapp.storage; + +public class ArrayStorageTest extends AbstractArrayStorageTest { + + public ArrayStorageTest() { + super(new ArrayStorage()); + } +} diff --git a/test/com/urise/webapp/storage/DataPathStorageTest.java b/test/com/urise/webapp/storage/DataPathStorageTest.java new file mode 100644 index 00000000..01ebab92 --- /dev/null +++ b/test/com/urise/webapp/storage/DataPathStorageTest.java @@ -0,0 +1,11 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.storage.serializer.DataStreamSerializer; +import com.urise.webapp.storage.serializer.JsonStreamSerializer; + +public class DataPathStorageTest extends AbstractStorageTest { + + public DataPathStorageTest() { + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new DataStreamSerializer())); + } +} diff --git a/test/com/urise/webapp/storage/JsonPathStorageTest.java b/test/com/urise/webapp/storage/JsonPathStorageTest.java new file mode 100644 index 00000000..17e55066 --- /dev/null +++ b/test/com/urise/webapp/storage/JsonPathStorageTest.java @@ -0,0 +1,10 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.storage.serializer.JsonStreamSerializer; + +public class JsonPathStorageTest extends AbstractStorageTest { + + public JsonPathStorageTest() { + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new JsonStreamSerializer())); + } +} diff --git a/test/com/urise/webapp/storage/ListStorageTest.java b/test/com/urise/webapp/storage/ListStorageTest.java new file mode 100644 index 00000000..232c5f9e --- /dev/null +++ b/test/com/urise/webapp/storage/ListStorageTest.java @@ -0,0 +1,7 @@ +package com.urise.webapp.storage; + +public class ListStorageTest extends AbstractStorageTest { + public ListStorageTest() { + super(new ListStorage()); + } +} diff --git a/test/com/urise/webapp/storage/MapResumeStorageTest.java b/test/com/urise/webapp/storage/MapResumeStorageTest.java new file mode 100644 index 00000000..0cdf600b --- /dev/null +++ b/test/com/urise/webapp/storage/MapResumeStorageTest.java @@ -0,0 +1,8 @@ +package com.urise.webapp.storage; + +public class MapResumeStorageTest extends AbstractStorageTest { + + public MapResumeStorageTest() { + super(new MapResumeStorage()); + } +} diff --git a/test/com/urise/webapp/storage/MapStorageTest.java b/test/com/urise/webapp/storage/MapStorageTest.java new file mode 100644 index 00000000..ba014a81 --- /dev/null +++ b/test/com/urise/webapp/storage/MapStorageTest.java @@ -0,0 +1,8 @@ +package com.urise.webapp.storage; + +public class MapStorageTest extends AbstractStorageTest { + + public MapStorageTest() { + super(new MapStorage()); + } +} diff --git a/test/com/urise/webapp/storage/ObjectFileStorageTest.java b/test/com/urise/webapp/storage/ObjectFileStorageTest.java new file mode 100644 index 00000000..adade8d5 --- /dev/null +++ b/test/com/urise/webapp/storage/ObjectFileStorageTest.java @@ -0,0 +1,9 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.storage.serializer.ObjectStreamSerializer; + +public class ObjectFileStorageTest extends AbstractStorageTest { + public ObjectFileStorageTest() { + super(new FileStorage(STORAGE_DIR, new ObjectStreamSerializer())); + } +} diff --git a/test/com/urise/webapp/storage/ObjectPathStorageTest.java b/test/com/urise/webapp/storage/ObjectPathStorageTest.java new file mode 100644 index 00000000..da636046 --- /dev/null +++ b/test/com/urise/webapp/storage/ObjectPathStorageTest.java @@ -0,0 +1,10 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.storage.serializer.ObjectStreamSerializer; + +public class ObjectPathStorageTest extends AbstractStorageTest { + + public ObjectPathStorageTest() { + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new ObjectStreamSerializer())); + } +} diff --git a/test/com/urise/webapp/storage/ResumeDataTest.java b/test/com/urise/webapp/storage/ResumeDataTest.java new file mode 100644 index 00000000..d8671edc --- /dev/null +++ b/test/com/urise/webapp/storage/ResumeDataTest.java @@ -0,0 +1,66 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.model.*; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class ResumeDataTest { + + public static Resume fillResumeSections(Resume r, int countJobOrganization, int countEducationOrganization, int countQualification, int countAchivements) { + + List organizationList = new ArrayList<>(); + List positions=new ArrayList<>(); + for (int i = 0; i < countJobOrganization; i++) { + positions = getPositions(i); + organizationList.add(new Organization( + "JOB_" + i, + "http://job_" + 1 + ".org", + positions)); + } + + List educationList = new ArrayList<>(); + List eduPositions; + for (int i = 0; i < countEducationOrganization; i++) { + eduPositions = getPositions(i); + educationList.add(new Organization( + "Education_" + i, + "http://education_" + 1 + ".org", + eduPositions + )); + } + + List qualifications = new ArrayList<>(); + for (int i = 0; i < countQualification; i++) { + qualifications.add("This is string №" + i + " describing qualifications!"); + } + + List achivements = new ArrayList<>(); + for (int i = 0; i < countAchivements; i++) { + achivements.add("This is string №" + i + " describing achievements!"); + } + r.addSection(SectionType.PERSONAL, new TextSection("This is describing string of myown!")); + r.addSection(SectionType.OBJECTIVE, new TextSection("This is describing string of willing position!")); + r.addSection(SectionType.QUALIFICATIONS, new ListSection(qualifications)); + r.addSection(SectionType.ACHIEVEMENT, new ListSection(achivements)); + r.addSection(SectionType.EXPERIENCE, new OrganizationSection(organizationList)); + r.addSection(SectionType.EDUCATION, new OrganizationSection(educationList)); + r.addContact(ContactType.MAIL, "mail@mail.ru"); + r.addContact(ContactType.PHONE, "1111-11-1111"); + return r; + } + + private static List getPositions(int organizationNumber) { + List positions = new ArrayList<>(); + for (int j = 0; j < 3; j++) { + positions.add(new Organization.Position( + LocalDate.of(2000 + j, 1, 1), + LocalDate.of(2001 + j, 12, 31), + "Position title " + organizationNumber + "_" + j, + "Position description " + organizationNumber + "_" + j + )); + } + return positions; + } +} diff --git a/test/com/urise/webapp/storage/SortedArrayStorageTest.java b/test/com/urise/webapp/storage/SortedArrayStorageTest.java new file mode 100644 index 00000000..b053ec41 --- /dev/null +++ b/test/com/urise/webapp/storage/SortedArrayStorageTest.java @@ -0,0 +1,9 @@ +package com.urise.webapp.storage; + +public class SortedArrayStorageTest extends AbstractArrayStorageTest { + + public SortedArrayStorageTest() { + super(new SortedArrayStorage()); + } + +} \ No newline at end of file diff --git a/test/com/urise/webapp/storage/SqlStorageTest.java b/test/com/urise/webapp/storage/SqlStorageTest.java new file mode 100644 index 00000000..95be3ac7 --- /dev/null +++ b/test/com/urise/webapp/storage/SqlStorageTest.java @@ -0,0 +1,12 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.Config; + +public class SqlStorageTest extends AbstractStorageTest { + + public SqlStorageTest() { + super(new SqlStorage(Config.getInstance().getDbUrl(), + Config.getInstance().getDbUser(), + Config.getInstance().getDbPassword())); + } +} diff --git a/test/com/urise/webapp/storage/XmlPathStorageTest.java b/test/com/urise/webapp/storage/XmlPathStorageTest.java new file mode 100644 index 00000000..70dd40f4 --- /dev/null +++ b/test/com/urise/webapp/storage/XmlPathStorageTest.java @@ -0,0 +1,11 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.storage.serializer.ObjectStreamSerializer; +import com.urise.webapp.storage.serializer.XmlStreamSerializer; + +public class XmlPathStorageTest extends AbstractStorageTest { + + public XmlPathStorageTest() { + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new XmlStreamSerializer())); + } +}