diff --git a/TEMP/uuid3 b/TEMP/uuid3 new file mode 100644 index 00000000..3cd6d099 Binary files /dev/null and b/TEMP/uuid3 differ 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/populate.sql b/config/populate.sql new file mode 100644 index 00000000..cbcc93f3 --- /dev/null +++ b/config/populate.sql @@ -0,0 +1,4 @@ +INSERT INTO resumes (uuid, full_name) VALUES + ('7de882da-02f2-4d16-8daa-60660aaf4071', 'Name1'), + ('a97b3ac3-3817-4c3f-8a5f-178497311f1d', 'Name2'), + ('dd0a70d1-5ed3-479a-b452-d5e04f21ca73', 'Name3'); \ No newline at end of file diff --git a/config/populateContact.sql b/config/populateContact.sql new file mode 100644 index 00000000..f476eb2d --- /dev/null +++ b/config/populateContact.sql @@ -0,0 +1,3 @@ +INSERT INTO contact (resume_uuid, type, value) VALUES + ('dd0a70d1-5ed3-479a-b452-d5e04f21ca73', 'PHONE','380505132950'), + ('dd0a70d1-5ed3-479a-b452-d5e04f21ca73', 'SKYPE', 'ip500800') ; \ No newline at end of file diff --git a/config/resumes.properties b/config/resumes.properties new file mode 100644 index 00000000..f818a955 --- /dev/null +++ b/config/resumes.properties @@ -0,0 +1,4 @@ +storage.dir=C:/projects/basejava/storage +db.url=jdbc:postgresql://localhost:5432/postgres +db.user=postgres +db.password=a \ No newline at end of file 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/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/ru/javawebinar/basejava/Config.java b/src/ru/javawebinar/basejava/Config.java new file mode 100644 index 00000000..fe695a29 --- /dev/null +++ b/src/ru/javawebinar/basejava/Config.java @@ -0,0 +1,41 @@ +package ru.javawebinar.basejava; + +import ru.javawebinar.basejava.storage.SqlStorage; +import ru.javawebinar.basejava.storage.Storage; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class Config { + private static final File PROPS = new File("config\\resumes.properties"); + private static final Config INSTANCE = new Config(); + + private final File storageDir; + private final Storage storage; + + public static Config get() { + return INSTANCE; + } + + private Config() { + try (InputStream is = new FileInputStream(PROPS)) { + Properties props = new Properties(); + props.load(is); + storageDir = new File(props.getProperty("storage.dir")); + storage = new SqlStorage(props.getProperty("db.url"), props.getProperty("db.user"), props.getProperty("db.password")); + } catch (IOException e) { + throw new IllegalStateException("Invalid config file " + PROPS.getAbsolutePath()); + } + } + + public File getStorageDir() { + return storageDir; + } + + public Storage getStorage() { + return storage; +} +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/LazySingleton.java b/src/ru/javawebinar/basejava/LazySingleton.java new file mode 100644 index 00000000..223ce3f7 --- /dev/null +++ b/src/ru/javawebinar/basejava/LazySingleton.java @@ -0,0 +1,24 @@ +package ru.javawebinar.basejava; + +public class LazySingleton { + volatile private static LazySingleton INSTANCE; + + private LazySingleton() { + } + + private static class LazySingletonHolder { + private static final LazySingleton INSTANCE = new LazySingleton(); + } + + public static LazySingleton getInstance() { + return LazySingletonHolder.INSTANCE; +// if (INSTANCE == null) { +// synchronized (LazySingleton.class) { +// if (INSTANCE == null) { +// INSTANCE = new LazySingleton(); +// } +// } +// } +// return INSTANCE; + } +} \ No newline at end of file diff --git a/src/MainArray.java b/src/ru/javawebinar/basejava/MainArray.java similarity index 63% rename from src/MainArray.java rename to src/ru/javawebinar/basejava/MainArray.java index b1cb33b7..9383f3c1 100644 --- a/src/MainArray.java +++ b/src/ru/javawebinar/basejava/MainArray.java @@ -1,27 +1,33 @@ +package ru.javawebinar.basejava; + +import ru.javawebinar.basejava.model.Resume; +import ru.javawebinar.basejava.storage.ArrayStorage; +import ru.javawebinar.basejava.storage.Storage; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.util.List; /** - * Interactive test for ArrayStorage implementation - * (just run, no need to understand) + * Test for ru.javawebinar.basejava.storage.ArrayStorage */ public class MainArray { - private final static ArrayStorage ARRAY_STORAGE = new ArrayStorage(); + private final static Storage 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): "); + System.out.print("Введите одну из команд - (list | save fullName | delete uuid | get uuid | update uuid fullName | clear | exit): "); String[] params = reader.readLine().trim().toLowerCase().split(" "); - if (params.length < 1 || params.length > 2) { + if (params.length < 1 || params.length > 3) { System.out.println("Неверная команда."); continue; } - String uuid = null; - if (params.length == 2) { - uuid = params[1].intern(); + String param = null; + if (params.length > 1) { + param = params[1].intern(); } switch (params[0]) { case "list": @@ -31,17 +37,21 @@ public static void main(String[] args) throws IOException { System.out.println(ARRAY_STORAGE.size()); break; case "save": - r = new Resume(); - r.uuid = uuid; + r = new Resume(param); ARRAY_STORAGE.save(r); printAll(); break; + case "update": + r = new Resume(param, params[2]); + ARRAY_STORAGE.update(r); + printAll(); + break; case "delete": - ARRAY_STORAGE.delete(uuid); + ARRAY_STORAGE.delete(param); printAll(); break; case "get": - System.out.println(ARRAY_STORAGE.get(uuid)); + System.out.println(ARRAY_STORAGE.get(param)); break; case "clear": ARRAY_STORAGE.clear(); @@ -57,9 +67,9 @@ public static void main(String[] args) throws IOException { } static void printAll() { - Resume[] all = ARRAY_STORAGE.getAll(); + List all = ARRAY_STORAGE.getAllSorted(); System.out.println("----------------------------"); - if (all.length == 0) { + if (all.size() == 0) { System.out.println("Empty"); } else { for (Resume r : all) { diff --git a/src/ru/javawebinar/basejava/MainCollections.java b/src/ru/javawebinar/basejava/MainCollections.java new file mode 100644 index 00000000..11aab226 --- /dev/null +++ b/src/ru/javawebinar/basejava/MainCollections.java @@ -0,0 +1,62 @@ +package ru.javawebinar.basejava; + +import ru.javawebinar.basejava.model.Resume; + +import java.util.*; + +public class MainCollections { + private static final String UUID_1 = "uuid1"; + private static final Resume RESUME_1 = new Resume(UUID_1, "Name1"); + + private static final String UUID_2 = "uuid2"; + private static final Resume RESUME_2 = new Resume(UUID_2, "Name2"); + + private static final String UUID_3 = "uuid3"; + private static final Resume RESUME_3 = new Resume(UUID_3, "Name3"); + + private static final String UUID_4 = "uuid4"; + private static final Resume RESUME_4 = new Resume(UUID_4, "Name4"); + + public static void main(String[] args) { + Collection collection = new ArrayList<>(); + collection.add(RESUME_1); + collection.add(RESUME_2); + collection.add(RESUME_3); + + for (Resume r : collection) { + System.out.println(r); + if (Objects.equals(r.getUuid(), UUID_1)) { +// collection.remove(r); + } + } + + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + Resume r = iterator.next(); + System.out.println(r); + if (Objects.equals(r.getUuid(), UUID_1)) { + iterator.remove(); + } + } + System.out.println(collection.toString()); + + + Map map = new HashMap<>(); + map.put(UUID_1, RESUME_1); + map.put(UUID_2, RESUME_2); + map.put(UUID_3, RESUME_3); + + // Bad! + for (String uuid : map.keySet()) { + System.out.println(map.get(uuid)); + } + + for (Map.Entry entry : map.entrySet()) { + System.out.println(entry.getValue()); + } + + List resumes = Arrays.asList(RESUME_1, RESUME_2, RESUME_3); + resumes.remove(1); + System.out.println(resumes); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/MainConcurrency.java b/src/ru/javawebinar/basejava/MainConcurrency.java new file mode 100644 index 00000000..ab57affe --- /dev/null +++ b/src/ru/javawebinar/basejava/MainConcurrency.java @@ -0,0 +1,136 @@ +package ru.javawebinar.basejava; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * gkislin + * 29.08.2016 + */ +public class MainConcurrency { + public static final int THREADS_NUMBER = 10000; + private int counter; + private final AtomicInteger atomicCounter = new AtomicInteger(); + + // private static final Object LOCK = new Object(); +// private static final Lock lock = new ReentrantLock(); + private static final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); + private static final Lock WRITE_LOCK = reentrantReadWriteLock.writeLock(); + private static final Lock READ_LOCK = reentrantReadWriteLock.readLock(); + private static final ThreadLocal threadLocal = new ThreadLocal() { + @Override + protected SimpleDateFormat initialValue() { + return new SimpleDateFormat(); + } + }; + + public static void main(String[] args) throws InterruptedException { + System.out.println(Thread.currentThread().getName()); + + Thread thread0 = new Thread() { + @Override + public void run() { + System.out.println(getName() + ", " + getState()); +// throw new IllegalStateException(); + } + }; + thread0.start(); + + new Thread(new Runnable() { + + @Override + public void run() { + System.out.println(Thread.currentThread().getName() + ", " + Thread.currentThread().getState()); + } + + private void inc() { + synchronized (this) { +// counter++; + } + } + + }).start(); + + System.out.println(thread0.getState()); + + final MainConcurrency mainConcurrency = new MainConcurrency(); + CountDownLatch latch = new CountDownLatch(THREADS_NUMBER); + ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); +// CompletionService completionService = new ExecutorCompletionService(executorService); +// +// List threads = new ArrayList<>(THREADS_NUMBER); + + for (int i = 0; i < THREADS_NUMBER; i++) { + + Future future = executorService.submit(() -> +// Thread thread = new Thread(() -> + { + for (int j = 0; j < 100; j++) { + mainConcurrency.inc(); + System.out.println(threadLocal.get().format(new Date())); + } + latch.countDown(); + return 5; + }); +// thread.start(); +// threads.add(thread); + } + +/* + threads.forEach(t -> { + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); +*/ + latch.await(10, TimeUnit.SECONDS); + executorService.shutdown(); +// System.out.println(mainConcurrency.counter); + System.out.println(mainConcurrency.atomicCounter.get()); + +// final String lock1 = "lock1"; +// final String lock2 = "lock2"; +// deadLock(lock1, lock2); +// deadLock(lock2, lock1); + } + + private static void deadLock(Object lock1, Object lock2) { + new Thread(() -> { + System.out.println("Waiting " + lock1); + synchronized (lock1) { + System.out.println("Holding " + lock1); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Waiting " + lock2); + synchronized (lock2) { + System.out.println("Holding " + lock2); + } + } + }).start(); + } + + private void inc() { +// synchronized (this) { +// synchronized (MainConcurrency.class) { +// WRITE_LOCK.lock(); +// try { + atomicCounter.incrementAndGet(); +// counter++; +// } finally { +// WRITE_LOCK.unlock(); +// } +// wait(); +// readFile +// ... +// } + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/MainDate.java b/src/ru/javawebinar/basejava/MainDate.java new file mode 100644 index 00000000..6e57aa93 --- /dev/null +++ b/src/ru/javawebinar/basejava/MainDate.java @@ -0,0 +1,38 @@ +package ru.javawebinar.basejava; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +/** + * gkislin + * 20.07.2016 + */ +public class MainDate { + public static void main(String[] args) { + long start = System.currentTimeMillis(); + Date date = new Date(); + System.out.println(date); + System.out.println(System.currentTimeMillis() - start); + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); + System.out.println(cal.getTime()); + + LocalDate ld = LocalDate.now(); + LocalTime lt = LocalTime.now(); + LocalDateTime ldt = LocalDateTime.of(ld, lt); + System.out.println(ldt); + + + SimpleDateFormat sdf = new SimpleDateFormat("YY/MM/dd"); + System.out.println(sdf.format(date)); + + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YY/MM/dd"); + System.out.println(dtf.format(ldt)); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/MainReflection.java b/src/ru/javawebinar/basejava/MainReflection.java new file mode 100644 index 00000000..7fa17969 --- /dev/null +++ b/src/ru/javawebinar/basejava/MainReflection.java @@ -0,0 +1,24 @@ +package ru.javawebinar.basejava; + +import ru.javawebinar.basejava.model.Resume; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class MainReflection { + + public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + Resume r = new Resume("Name"); + Class resumeClass = r.getClass(); + Field field = resumeClass.getDeclaredFields()[0]; + field.setAccessible(true); + System.out.println(field.getName()); + System.out.println(field.get(r)); + field.set(r, "new_uuid"); + + Method method = resumeClass.getMethod("toString"); + Object result = method.invoke(r); + System.out.println(result); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/MainString.java b/src/ru/javawebinar/basejava/MainString.java new file mode 100644 index 00000000..681b1896 --- /dev/null +++ b/src/ru/javawebinar/basejava/MainString.java @@ -0,0 +1,18 @@ +package ru.javawebinar.basejava; + +public class MainString { + public static void main(String[] args) { + String[] strArray = new String[]{"1", "2", "3", "4", "5"}; +// String result = ""; + StringBuilder sb = new StringBuilder(); + for (String str : strArray) { + sb.append(str).append(", "); + } + System.out.println(sb.toString()); + + String str1 = "abc"; + String str3 = "c"; + String str2 = ("ab" + str3).intern(); + System.out.println(str1 == str2); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/MainUtil.java b/src/ru/javawebinar/basejava/MainUtil.java new file mode 100644 index 00000000..893e1cfc --- /dev/null +++ b/src/ru/javawebinar/basejava/MainUtil.java @@ -0,0 +1,14 @@ +package ru.javawebinar.basejava; + +public class MainUtil { + public static void main(String[] args) { + System.out.println(Integer.valueOf(-1) == Integer.valueOf(-1)); + System.out.println(Integer.valueOf(-1) == new Integer(-1)); + int result = getInt(); + System.out.println(result); + } + + private static Integer getInt() { + return null; + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/TestSingleton.java b/src/ru/javawebinar/basejava/TestSingleton.java new file mode 100644 index 00000000..0c28439c --- /dev/null +++ b/src/ru/javawebinar/basejava/TestSingleton.java @@ -0,0 +1,31 @@ +package ru.javawebinar.basejava; + +import ru.javawebinar.basejava.model.SectionType; + +public class TestSingleton { + private static TestSingleton instance; + + public static TestSingleton getInstance() { + if (instance == null) { + instance = new TestSingleton(); + } + return instance; + } + + private TestSingleton() { + } + + public static void main(String[] args) { + TestSingleton.getInstance().toString(); + Singleton instance = Singleton.valueOf("INSTANCE"); + System.out.println(instance.ordinal()); + + for (SectionType type : SectionType.values()) { + System.out.println(type.getTitle()); + } + } + + public enum Singleton { + INSTANCE + } +} diff --git a/src/ru/javawebinar/basejava/exception/ExistStorageException.java b/src/ru/javawebinar/basejava/exception/ExistStorageException.java new file mode 100644 index 00000000..33d98be0 --- /dev/null +++ b/src/ru/javawebinar/basejava/exception/ExistStorageException.java @@ -0,0 +1,7 @@ +package ru.javawebinar.basejava.exception; + +public class ExistStorageException extends StorageException { + public ExistStorageException(String uuid) { + super("Resume " + uuid + " already exist", uuid); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/exception/NotExistStorageException.java b/src/ru/javawebinar/basejava/exception/NotExistStorageException.java new file mode 100644 index 00000000..8e4dfff5 --- /dev/null +++ b/src/ru/javawebinar/basejava/exception/NotExistStorageException.java @@ -0,0 +1,7 @@ +package ru.javawebinar.basejava.exception; + +public class NotExistStorageException extends StorageException { + public NotExistStorageException(String uuid) { + super("Resume " + uuid + " not exist", uuid); + } +} diff --git a/src/ru/javawebinar/basejava/exception/StorageException.java b/src/ru/javawebinar/basejava/exception/StorageException.java new file mode 100644 index 00000000..6a3419f2 --- /dev/null +++ b/src/ru/javawebinar/basejava/exception/StorageException.java @@ -0,0 +1,31 @@ +package ru.javawebinar.basejava.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(Exception e) { + this(e.getMessage(), e); + } + + public StorageException(String message, Exception e) { + this(message, null, e); + } + + public StorageException(String message, String uuid, Exception e) { + super(message, e); + this.uuid = uuid; + } + + public String getUuid() { + return uuid; + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/model/Resume.java b/src/ru/javawebinar/basejava/model/Resume.java new file mode 100644 index 00000000..bc5b0955 --- /dev/null +++ b/src/ru/javawebinar/basejava/model/Resume.java @@ -0,0 +1,97 @@ +package ru.javawebinar.basejava.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; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD)// Работай с полями смотри на поля а не на гетеры и сетеры +public class Resume implements Comparable, Serializable { + private 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(uuid, "uuid must not be null"); + Objects.requireNonNull(fullName, "fullName must not be null"); + this.uuid = uuid; + this.fullName = fullName; + } + + public String getUuid() { + return uuid; + } + + public String getFullName() { + return fullName; + } + + public Map getContacts() { + return contacts; + } + + public Map getSections() { + return sections; + } + + public String getContact(ContactType type) { + return contacts.get(type); + } + + public Section getSection(SectionType type) { + return sections.get(type); + } + + public void addContact(ContactType type, String value) { + contacts.put(type, value); + } + + public void addSection(SectionType type, Section section) { + sections.put(type, section); + } + + @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); + } + + @Override + public String toString() { + return uuid + '(' + fullName + ')'; + } + + @Override + public int compareTo(Resume o) { + int cmp = fullName.compareTo(o.fullName); + return cmp != 0 ? cmp : uuid.compareTo(o.uuid); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/model/SectionType.java b/src/ru/javawebinar/basejava/model/SectionType.java new file mode 100644 index 00000000..006eeeef --- /dev/null +++ b/src/ru/javawebinar/basejava/model/SectionType.java @@ -0,0 +1,21 @@ + +package ru.javawebinar.basejava.model; + +public enum SectionType { + PERSONAL("Личные качества"), + OBJECTIVE("Позиция"), + ACHIEVEMENT("Достижения"), + QUALIFICATIONS("Квалификация"), + EXPERIENCE("Опыт работы"), + EDUCATION("Образование"); + + private String title; + + SectionType(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/sql/ConnectionFactory.java b/src/ru/javawebinar/basejava/sql/ConnectionFactory.java new file mode 100644 index 00000000..b6e4f0d7 --- /dev/null +++ b/src/ru/javawebinar/basejava/sql/ConnectionFactory.java @@ -0,0 +1,8 @@ +package ru.javawebinar.basejava.sql; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface ConnectionFactory { + Connection getConnection() throws SQLException; +} diff --git a/src/ru/javawebinar/basejava/sql/ExceptionUtil.java b/src/ru/javawebinar/basejava/sql/ExceptionUtil.java new file mode 100644 index 00000000..35228a17 --- /dev/null +++ b/src/ru/javawebinar/basejava/sql/ExceptionUtil.java @@ -0,0 +1,23 @@ +package ru.javawebinar.basejava.sql; + +import org.postgresql.util.PSQLException; +import ru.javawebinar.basejava.exception.ExistStorageException; +import ru.javawebinar.basejava.exception.StorageException; + +import java.sql.SQLException; + +public class ExceptionUtil { + private ExceptionUtil() { + } + + public static StorageException convertException(SQLException e) { + if (e instanceof PSQLException) { + +// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html + if (e.getSQLState().equals("23505")) { + return new ExistStorageException(null); + } + } + return new StorageException(e); + } +} diff --git a/src/ru/javawebinar/basejava/sql/SqlHelper.java b/src/ru/javawebinar/basejava/sql/SqlHelper.java new file mode 100644 index 00000000..5b5061c9 --- /dev/null +++ b/src/ru/javawebinar/basejava/sql/SqlHelper.java @@ -0,0 +1,44 @@ +package ru.javawebinar.basejava.sql; + +import ru.javawebinar.basejava.exception.StorageException; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class SqlHelper { + private final ConnectionFactory connectionFactory; + + public SqlHelper(ConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + } + + public void execute(String sql) { + execute(sql, PreparedStatement::execute); + } + + public T execute(String sql, SqlExecutor executor) { + try (Connection conn = connectionFactory.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + return executor.execute(ps); + } catch (SQLException e) { + throw ExceptionUtil.convertException(e); + } + } + + public T transactionalExecute(SqlTransaction executor) { + try (Connection conn = connectionFactory.getConnection()) { + try { + conn.setAutoCommit(false); + T res = executor.execute(conn); + conn.commit(); + return res; + } catch (SQLException e) { + conn.rollback(); + throw ExceptionUtil.convertException(e); + } + } catch (SQLException e) { + throw new StorageException(e); + } + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/sql/SqlTransaction.java b/src/ru/javawebinar/basejava/sql/SqlTransaction.java new file mode 100644 index 00000000..bdc04431 --- /dev/null +++ b/src/ru/javawebinar/basejava/sql/SqlTransaction.java @@ -0,0 +1,8 @@ +package ru.javawebinar.basejava.sql; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface SqlTransaction { + T execute(Connection conn) throws SQLException; +} diff --git a/src/ru/javawebinar/basejava/storage/AbstractArrayStorage.java b/src/ru/javawebinar/basejava/storage/AbstractArrayStorage.java new file mode 100644 index 00000000..f59b5f57 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/AbstractArrayStorage.java @@ -0,0 +1,71 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.exception.StorageException; +import ru.javawebinar.basejava.model.Resume; + +import java.util.Arrays; +import java.util.List; + +/** + * Array based storage for Resumes + */ +public abstract class AbstractArrayStorage extends AbstractStorage { + protected static final int STORAGE_LIMIT = 10000; + + protected Resume[] storage = new Resume[STORAGE_LIMIT]; + protected int size = 0; + + public int size() { + return size; + } + + public void clear() { + Arrays.fill(storage, 0, size, null); + size = 0; + } + + @Override + protected void doUpdate(Resume r, Integer index) { + storage[index] = r; + } + + /** + * @return array, contains only Resumes in storage (without null) + */ + @Override + public List doCopyAll() { + return Arrays.asList(Arrays.copyOfRange(storage, 0, size)); + } + + @Override + protected void doSave(Resume r, Integer index) { + if (size == STORAGE_LIMIT) { + throw new StorageException("Storage overflow", r.getUuid()); + } else { + insertElement(r, index); + size++; + } + } + + @Override + public void doDelete(Integer index) { + fillDeletedElement(index); + storage[size - 1] = null; + size--; + } + + public Resume doGet(Integer index) { + return storage[index]; + } + + @Override + protected boolean isExist(Integer index) { + return index >= 0; + } + + protected abstract void fillDeletedElement(int index); + + protected abstract void insertElement(Resume r, int index); + + protected abstract Integer getSearchKey(String uuid); +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/AbstractStorage.java b/src/ru/javawebinar/basejava/storage/AbstractStorage.java new file mode 100644 index 00000000..e8f34496 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/AbstractStorage.java @@ -0,0 +1,79 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.exception.ExistStorageException; +import ru.javawebinar.basejava.exception.NotExistStorageException; +import ru.javawebinar.basejava.model.Resume; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +public abstract class AbstractStorage implements Storage { + + // protected final Logger LOG = Logger.getLogger(getClass().getName()); + private static final Logger LOG = Logger.getLogger(AbstractStorage.class.getName()); + + protected abstract SK getSearchKey(String uuid); + + protected abstract void doUpdate(Resume r, SK searchKey); + + protected abstract boolean isExist(SK searchKey); + + protected abstract void doSave(Resume r, SK searchKey); + + protected abstract Resume doGet(SK searchKey); + + protected abstract void doDelete(SK searchKey); + + protected abstract List doCopyAll(); + + public void update(Resume r) { + LOG.info("Update " + r); + SK searchKey = getExistedSearchKey(r.getUuid()); + doUpdate(r, searchKey); + } + + public void save(Resume r) { + LOG.info("Save " + r); + SK searchKey = getNotExistedSearchKey(r.getUuid()); + doSave(r, searchKey); + } + + public void delete(String uuid) { + LOG.info("Delete " + uuid); + SK searchKey = getExistedSearchKey(uuid); + doDelete(searchKey); + } + + public Resume get(String uuid) { + LOG.info("Get " + uuid); + SK searchKey = getExistedSearchKey(uuid); + return doGet(searchKey); + } + + private SK getExistedSearchKey(String uuid) { + SK searchKey = getSearchKey(uuid); + if (!isExist(searchKey)) { + LOG.warning("Resume " + uuid + " not exist"); + throw new NotExistStorageException(uuid); + } + return searchKey; + } + + private SK getNotExistedSearchKey(String uuid) { + SK searchKey = getSearchKey(uuid); + if (isExist(searchKey)) { + LOG.warning("Resume " + uuid + " already exist"); + throw new ExistStorageException(uuid); + } + return searchKey; + } + + @Override + public List getAllSorted() { + LOG.info("getAllSorted"); + List list = doCopyAll(); + Collections.sort(list); + return list; +} +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/ArrayStorage.java b/src/ru/javawebinar/basejava/storage/ArrayStorage.java new file mode 100644 index 00000000..b9722d87 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/ArrayStorage.java @@ -0,0 +1,28 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.model.Resume; + +/** + * Array based storage for Resumes + */ +public class ArrayStorage extends AbstractArrayStorage { + + @Override + protected void fillDeletedElement(int index) { + storage[index] = storage[size - 1]; + } + + @Override + protected void insertElement(Resume r, int index) { + storage[size] = r; + } + + protected Integer getSearchKey(String uuid) { + for (int i = 0; i < size; i++) { + if (uuid.equals(storage[i].getUuid())) { + return i; + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/FileStorage.java b/src/ru/javawebinar/basejava/storage/FileStorage.java new file mode 100644 index 00000000..438e540b --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/FileStorage.java @@ -0,0 +1,110 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.exception.StorageException; +import ru.javawebinar.basejava.model.Resume; +import ru.javawebinar.basejava.storage.serializer.StreamSerializer; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * gkislin + * 22.07.2016 + */ +public class FileStorage extends AbstractStorage { + private File directory; + + private StreamSerializer streamSerializer; + + protected FileStorage(File directory, StreamSerializer streamSerializer) { + Objects.requireNonNull(directory, "directory must not be 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 + public void clear() { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + doDelete(file); + } + } + } + + @Override + public int size() { + String[] list = directory.list(); + if (list == null) { + throw new StorageException("Directory read error"); + } + return list.length; + } + + @Override + protected File getSearchKey(String uuid) { + return new File(directory, uuid); + } + + @Override + protected void doUpdate(Resume r, File file) { + try { + streamSerializer.doWrite(r, new BufferedOutputStream(new FileOutputStream(file))); + } catch (IOException e) { + throw new StorageException("File write error", r.getUuid(), e); + } + } + + @Override + protected boolean isExist(File file) { + return file.exists(); + } + + @Override + protected void doSave(Resume r, File file) { + try { + file.createNewFile(); + } catch (IOException e) { + throw new StorageException("Couldn't create file " + file.getAbsolutePath(), file.getName(), e); + } + doUpdate(r, file); + } + + @Override + protected Resume doGet(File file) { + 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(File file) { + if (!file.delete()) { + throw new StorageException("File delete error", file.getName()); + } + } + + @Override + protected List doCopyAll() { + File[] files = directory.listFiles(); + if (files == null) { + throw new StorageException("Directory read error"); + } + List list = new ArrayList<>(files.length); + for (File file : files) { + list.add(doGet(file)); + } + return list; + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/ListStorage.java b/src/ru/javawebinar/basejava/storage/ListStorage.java new file mode 100644 index 00000000..d2e3d9c0 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/ListStorage.java @@ -0,0 +1,60 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.model.Resume; + +import java.util.ArrayList; +import java.util.List; + +public class ListStorage extends AbstractStorage { + private List list = new ArrayList<>(); + + @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 + protected boolean isExist(Integer searchKey) { + return searchKey != null; + } + + @Override + protected void doUpdate(Resume r, Integer searchKey) { + list.set(searchKey, r); + } + + @Override + protected void doSave(Resume r, Integer searchKey) { + list.add(r); + } + + @Override + protected Resume doGet(Integer searchKey) { + return list.get(searchKey); + } + + @Override + protected void doDelete(Integer searchKey) { + list.remove(searchKey.intValue()); + } + + @Override + public void clear() { + list.clear(); + } + + @Override + public List doCopyAll() { + return new ArrayList<>(list); + } + + @Override + public int size() { + return list.size(); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/MainUtil.java b/src/ru/javawebinar/basejava/storage/MainUtil.java new file mode 100644 index 00000000..a4d21ddb --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/MainUtil.java @@ -0,0 +1,14 @@ +package ru.javawebinar.basejava.storage; + +public class MainUtil { + public static void main(String[] args) { + System.out.println(Integer.valueOf(-1) == Integer.valueOf(-1)); + System.out.println(Integer.valueOf(-1) == new Integer(-1)); + int result = getInt(); + System.out.println(result); + } + + private static Integer getInt() { + return null; + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/MapResumeStorage.java b/src/ru/javawebinar/basejava/storage/MapResumeStorage.java new file mode 100644 index 00000000..27137eef --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/MapResumeStorage.java @@ -0,0 +1,57 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.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 map = new HashMap<>(); + + @Override + protected Resume getSearchKey(String uuid) { + return map.get(uuid); + } + + @Override + protected void doUpdate(Resume r, Resume resume) { + map.put(r.getUuid(), r); + } + + @Override + protected boolean isExist(Resume resume) { + return resume != null; + } + + @Override + protected void doSave(Resume r, Resume resume) { + map.put(r.getUuid(), r); + } + + @Override + protected Resume doGet(Resume resume) { + return resume; + } + + @Override + protected void doDelete(Resume resume) { + map.remove(resume.getUuid()); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public List doCopyAll() { + return new ArrayList<>(map.values()); + } + + @Override + public int size() { + return map.size(); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/MapUuidStorage.java b/src/ru/javawebinar/basejava/storage/MapUuidStorage.java new file mode 100644 index 00000000..8e2e0750 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/MapUuidStorage.java @@ -0,0 +1,57 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.model.Resume; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MapUuidStorage extends AbstractStorage { + private Map map = new HashMap<>(); + + @Override + protected String getSearchKey(String uuid) { + return uuid; + } + + @Override + protected void doUpdate(Resume r, String uuid) { + map.put(uuid, r); + } + + @Override + protected boolean isExist(String uuid) { + return map.containsKey(uuid); + } + + @Override + protected void doSave(Resume r, String uuid) { + map.put(uuid, r); + } + + @Override + protected Resume doGet(String uuid) { + return map.get(uuid); + } + + @Override + protected void doDelete(String uuid) { + map.remove(uuid); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public List doCopyAll() { + return new ArrayList<>(map.values()); + } + + @Override + public int size() { + return map.size(); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/PathStorage.java b/src/ru/javawebinar/basejava/storage/PathStorage.java new file mode 100644 index 00000000..3ac6de7d --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/PathStorage.java @@ -0,0 +1,106 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.exception.StorageException; +import ru.javawebinar.basejava.model.Resume; +import ru.javawebinar.basejava.storage.serializer.StreamSerializer; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +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; +import java.util.stream.Stream; + +public class PathStorage extends AbstractStorage { + private Path directory; + + private StreamSerializer streamSerializer; + + protected PathStorage(String dir, StreamSerializer streamSerializer) { + Objects.requireNonNull(dir, "directory must not be null"); + + this.streamSerializer = streamSerializer; + directory = Paths.get(dir); + if (!Files.isDirectory(directory) || !Files.isWritable(directory)) { + throw new IllegalArgumentException(dir + " is not directory or is not writable"); + } + } + + @Override + public void clear() { + getFilesList().forEach(this::doDelete); + } + + @Override + public int size() { + return (int) getFilesList().count(); + } + + @Override + protected Path getSearchKey(String uuid) { + return directory.resolve(uuid); + } + + @Override + protected void doUpdate(Resume r, Path path) { + try { + streamSerializer.doWrite(r, new BufferedOutputStream(Files.newOutputStream(path))); + } catch (IOException e) { + throw new StorageException("Path write error", r.getUuid(), e); + } + } + + @Override + protected boolean isExist(Path path) { + return Files.isRegularFile(path); + } + + @Override + protected void doSave(Resume r, Path path) { + try { + Files.createFile(path); + } catch (IOException e) { + throw new StorageException("Couldn't create path " + path, getFileName(path), e); + } + doUpdate(r, path); + } + + @Override + protected Resume doGet(Path path) { + try { + return streamSerializer.doRead(new BufferedInputStream(Files.newInputStream(path))); + } catch (IOException e) { + throw new StorageException("Path read error", getFileName(path), e); + } + } + + @Override + protected void doDelete(Path path) { + try { + Files.delete(path); + } catch (IOException e) { + throw new StorageException("Path delete error", getFileName(path), e); + } + } + + @Override + protected List doCopyAll() { + return getFilesList().map(this::doGet).collect(Collectors.toList()); + } + + private String getFileName(Path path) { + return path.getFileName().toString(); + } + + private Stream getFilesList() { + try { + return Files.list(directory); + } catch (IOException e) { + throw new StorageException("Directory read error", e); + } + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/SortedArrayStorage.java b/src/ru/javawebinar/basejava/storage/SortedArrayStorage.java new file mode 100644 index 00000000..4a7fb346 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/SortedArrayStorage.java @@ -0,0 +1,41 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.model.Resume; + +import java.util.Arrays; +import java.util.Comparator; + +public class SortedArrayStorage extends AbstractArrayStorage { +/* + private static class ResumeComparator implements Comparator { + @Override + public int compare(Resume o1, Resume o2) { + return o1.getUuid().compareTo(o2.getUuid()); + } + } +*/ + + private static final Comparator RESUME_COMPARATOR = (o1, o2) -> o1.getUuid().compareTo(o2.getUuid()); + + @Override + protected void fillDeletedElement(int index) { + int numMoved = size - index - 1; + if (numMoved > 0) { + System.arraycopy(storage, index + 1, storage, index, numMoved); + } + } + + @Override + protected void insertElement(Resume r, int index) { +// http://codereview.stackexchange.com/questions/36221/binary-search-for-inserting-in-array#answer-36239 + int insertIdx = -index - 1; + System.arraycopy(storage, insertIdx, storage, insertIdx + 1, size - insertIdx); + storage[insertIdx] = r; + } + + @Override + protected Integer getSearchKey(String uuid) { + Resume searchKey = new Resume(uuid, "dummy"); + return Arrays.binarySearch(storage, 0, size, searchKey, RESUME_COMPARATOR); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/SqlStorage.java b/src/ru/javawebinar/basejava/storage/SqlStorage.java new file mode 100644 index 00000000..15d267da --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/SqlStorage.java @@ -0,0 +1,145 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.exception.NotExistStorageException; +import ru.javawebinar.basejava.model.ContactType; +import ru.javawebinar.basejava.model.Resume; +import ru.javawebinar.basejava.sql.SqlHelper; + +import java.sql.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +// TODO implement Section (except OrganizationSection) +// TODO Join and split ListSection by `\n` +public class SqlStorage implements Storage { + public final SqlHelper sqlHelper; + + public SqlStorage(String dbUrl, String dbUser, String dbPassword) { + sqlHelper = new SqlHelper(() -> DriverManager.getConnection(dbUrl, dbUser, dbPassword)); + } + + @Override + public void clear() { + sqlHelper.execute("DELETE FROM resume"); + } + + @Override + public Resume get(String uuid) { + return sqlHelper.execute("" + + " SELECT * FROM resume r " + + " LEFT JOIN contact c " + + " ON r.uuid = c.resume_uuid " + + " WHERE r.uuid =? ", + 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 { + addContact(rs, r); + } while (rs.next()); + + return r; + }); + } + + @Override + public void update(Resume r) { + sqlHelper.transactionalExecute(conn -> { + try (PreparedStatement ps = conn.prepareStatement("UPDATE resume SET full_name = ? WHERE uuid = ?")) { + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); + if (ps.executeUpdate() != 1) { + throw new NotExistStorageException(r.getUuid()); + } + } + deleteContacts(conn, r); + insertContact(conn, r); + return null; + }); + } + + @Override + public void save(Resume r) { + sqlHelper.transactionalExecute(conn -> { + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?,?)")) { + ps.setString(1, r.getUuid()); + ps.setString(2, r.getFullName()); + ps.execute(); + } + insertContact(conn, r); + return null; + }); + } + + @Override + public void delete(String uuid) { + sqlHelper.execute("DELETE FROM resume WHERE uuid=?", ps -> { + ps.setString(1, uuid); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(uuid); + } + return null; + }); + } + + @Override + public List getAllSorted() { + return sqlHelper.execute("" + + " SELECT * FROM resume r\n" + + "LEFT JOIN contact c ON r.uuid = c.resume_uuid\n" + + "ORDER BY full_name, uuid", ps -> { + ResultSet rs = ps.executeQuery(); + Map map = new LinkedHashMap<>(); + while (rs.next()) { + String uuid = rs.getString("uuid"); + Resume resume = map.get(uuid); + if (resume == null) { + resume = new Resume(uuid, rs.getString("full_name")); + map.put(uuid, resume); + } + addContact(rs, resume); + } + return new ArrayList<>(map.values()); + }); + } + + @Override + public int size() { + return sqlHelper.execute("SELECT count(*) FROM resume", st -> { + ResultSet rs = st.executeQuery(); + return rs.next() ? rs.getInt(1) : 0; + }); + } + + private void insertContact(Connection conn, Resume r) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { + for (Map.Entry e : r.getContacts().entrySet()) { + ps.setString(1, r.getUuid()); + ps.setString(2, e.getKey().name()); + ps.setString(3, e.getValue()); + ps.addBatch(); + } + ps.executeBatch(); + } + } + + private void deleteContacts(Connection conn, Resume r) { + sqlHelper.execute("DELETE FROM contact WHERE resume_uuid=?", ps -> { + ps.setString(1, r.getUuid()); + ps.execute(); + return null; + }); + } + + private void addContact(ResultSet rs, Resume r) throws SQLException { + String value = rs.getString("value"); + if (value != null) { + r.addContact(ContactType.valueOf(rs.getString("type")), value); + } + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/Storage.java b/src/ru/javawebinar/basejava/storage/Storage.java new file mode 100644 index 00000000..5af0da3d --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/Storage.java @@ -0,0 +1,25 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.model.Resume; + +import java.util.List; + +public interface Storage { + + void clear(); + + void update(Resume r); + + void save(Resume r); + + Resume get(String uuid); + + void delete(String uuid); + + /** + * @return array, contains only Resumes in storage (without null) + */ + List getAllSorted(); + + int size(); +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/serializer/DataStreamSerializer.java b/src/ru/javawebinar/basejava/storage/serializer/DataStreamSerializer.java new file mode 100644 index 00000000..5c8e2cdc --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/serializer/DataStreamSerializer.java @@ -0,0 +1,136 @@ +package ru.javawebinar.basejava.storage.serializer; + +import ru.javawebinar.basejava.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(); + Section 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()); + } + + private LocalDate readLocalDate(DataInputStream dis) throws IOException { + return LocalDate.of(dis.readInt(), dis.readInt(), 1); + } + + @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 Section 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/ru/javawebinar/basejava/storage/serializer/JsonStreamSerializer.java b/src/ru/javawebinar/basejava/storage/serializer/JsonStreamSerializer.java new file mode 100644 index 00000000..595f5476 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/serializer/JsonStreamSerializer.java @@ -0,0 +1,25 @@ +package ru.javawebinar.basejava.storage.serializer; + +import ru.javawebinar.basejava.model.Resume; +import ru.javawebinar.basejava.util.JsonParser; + +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 writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) { + JsonParser.write(r, writer); + } + } + + @Override + public Resume doRead(InputStream is) throws IOException { + try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + return JsonParser.read(reader, Resume.class); + } + } +} + diff --git a/src/ru/javawebinar/basejava/storage/serializer/ObjectStreamSerializer.java b/src/ru/javawebinar/basejava/storage/serializer/ObjectStreamSerializer.java new file mode 100644 index 00000000..5718c7a9 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/serializer/ObjectStreamSerializer.java @@ -0,0 +1,28 @@ +package ru.javawebinar.basejava.storage.serializer; + +import ru.javawebinar.basejava.exception.StorageException; +import ru.javawebinar.basejava.model.Resume; + +import java.io.*; + +/** + * Created by val on 2017-08-05. + */ +public class ObjectStreamSerializer implements StreamSerializer { + + @Override + public void doWrite(Resume r, OutputStream os) throws IOException { + try (ObjectOutputStream oos = new ObjectOutputStream(os)) { + oos.writeObject(r); + } + } + + @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); + } + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/storage/serializer/StreamSerializer.java b/src/ru/javawebinar/basejava/storage/serializer/StreamSerializer.java new file mode 100644 index 00000000..9f926047 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/serializer/StreamSerializer.java @@ -0,0 +1,16 @@ +package ru.javawebinar.basejava.storage.serializer; + +import ru.javawebinar.basejava.model.Resume; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Created by val on 2017-08-05. + */ +public interface StreamSerializer { + void doWrite(Resume r, OutputStream os) throws IOException; + + Resume doRead(InputStream is) throws IOException; +} diff --git a/src/ru/javawebinar/basejava/storage/serializer/XmlStreamSerializer.java b/src/ru/javawebinar/basejava/storage/serializer/XmlStreamSerializer.java new file mode 100644 index 00000000..c5c75a59 --- /dev/null +++ b/src/ru/javawebinar/basejava/storage/serializer/XmlStreamSerializer.java @@ -0,0 +1,31 @@ +package ru.javawebinar.basejava.storage.serializer; + +import ru.javawebinar.basejava.model.*; +import ru.javawebinar.basejava.util.XmlParser; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +public class XmlStreamSerializer implements StreamSerializer { + private XmlParser xmlParser; + + public XmlStreamSerializer() { + 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); + } + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/util/DateUtil.java b/src/ru/javawebinar/basejava/util/DateUtil.java new file mode 100644 index 00000000..1452b89e --- /dev/null +++ b/src/ru/javawebinar/basejava/util/DateUtil.java @@ -0,0 +1,17 @@ +package ru.javawebinar.basejava.util; + +import java.time.LocalDate; +import java.time.Month; + +/** + * gkislin + * 20.07.2016 + */ +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); + } +} \ No newline at end of file diff --git a/src/ru/javawebinar/basejava/util/JsonParser.java b/src/ru/javawebinar/basejava/util/JsonParser.java new file mode 100644 index 00000000..913b2582 --- /dev/null +++ b/src/ru/javawebinar/basejava/util/JsonParser.java @@ -0,0 +1,23 @@ +package ru.javawebinar.basejava.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import ru.javawebinar.basejava.model.Section; + +import java.io.Reader; +import java.io.Writer; + +public class JsonParser { + private static Gson GSON = new GsonBuilder() + .registerTypeAdapter(Section.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/ru/javawebinar/basejava/util/JsonSectionAdapter.java b/src/ru/javawebinar/basejava/util/JsonSectionAdapter.java new file mode 100644 index 00000000..e2d61457 --- /dev/null +++ b/src/ru/javawebinar/basejava/util/JsonSectionAdapter.java @@ -0,0 +1,34 @@ +package ru.javawebinar.basejava.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 json, Type type, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + 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(); + retValue.addProperty(CLASSNAME, section.getClass().getName()); + JsonElement elem = context.serialize(section); + retValue.add(INSTANCE, elem); + return retValue; + } +} diff --git a/src/ru/javawebinar/basejava/util/LocalDateAdapter.java b/src/ru/javawebinar/basejava/util/LocalDateAdapter.java new file mode 100644 index 00000000..3f22b250 --- /dev/null +++ b/src/ru/javawebinar/basejava/util/LocalDateAdapter.java @@ -0,0 +1,16 @@ +package ru.javawebinar.basejava.util; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.time.LocalDate; + +public class LocalDateAdapter extends XmlAdapter { + @Override + public LocalDate unmarshal(String str) throws Exception { + return LocalDate.parse(str); + } + + @Override + public String marshal(LocalDate ld) throws Exception { + return ld.toString(); + } +} diff --git a/src/ru/javawebinar/basejava/util/XmlParser.java b/src/ru/javawebinar/basejava/util/XmlParser.java new file mode 100644 index 00000000..6e7aa88e --- /dev/null +++ b/src/ru/javawebinar/basejava/util/XmlParser.java @@ -0,0 +1,47 @@ +package ru.javawebinar.basejava.util; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +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"); +// marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); + + 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/ru/javawebinar/basejava/web/ResumeServlet.java b/src/ru/javawebinar/basejava/web/ResumeServlet.java new file mode 100644 index 00000000..254d17e4 --- /dev/null +++ b/src/ru/javawebinar/basejava/web/ResumeServlet.java @@ -0,0 +1,21 @@ +package ru.javawebinar.basejava.web; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class ResumeServlet extends HttpServlet { + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { + + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { + request.setCharacterEncoding("UTF-8"); + response.setCharacterEncoding("UTF-8"); +// response.setHeader("Content-Type", "text/html; charset=UTF-8"); + response.setContentType("text/html; charset=UTF-8"); + String name = request.getParameter("name"); + response.getWriter().write(name == null ? "Hello Resumes!" : "Hello " + name + '!'); + } +} diff --git a/test/ru/javawebinar/basejava/storage/AbstractArrayStorageTest.java b/test/ru/javawebinar/basejava/storage/AbstractArrayStorageTest.java new file mode 100644 index 00000000..9bd85dd0 --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/AbstractArrayStorageTest.java @@ -0,0 +1,28 @@ +package ru.javawebinar.basejava.storage; + +import org.junit.Assert; +import org.junit.Test; +import ru.javawebinar.basejava.exception.StorageException; +import ru.javawebinar.basejava.model.Resume; + +/** + * gkislin + * 12.06.2016 + */ +public abstract class AbstractArrayStorageTest extends AbstractStorageTest { + protected AbstractArrayStorageTest(Storage storage) { + super(storage); + } + + @Test(expected = StorageException.class) + public void saveOverflow() throws Exception { + try { + for (int i = 4; i <= AbstractArrayStorage.STORAGE_LIMIT; i++) { + storage.save(new Resume("Name" + i)); + } + } catch (StorageException e) { + Assert.fail(); + } + storage.save(new Resume("Overflow")); + } +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/AbstractStorageTest.java b/test/ru/javawebinar/basejava/storage/AbstractStorageTest.java new file mode 100644 index 00000000..a6560f5c --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/AbstractStorageTest.java @@ -0,0 +1,161 @@ +package ru.javawebinar.basejava.storage; + +import org.junit.Before; +import org.junit.Test; +import ru.javawebinar.basejava.Config; +import ru.javawebinar.basejava.exception.ExistStorageException; +import ru.javawebinar.basejava.exception.NotExistStorageException; +import ru.javawebinar.basejava.model.ContactType; +import ru.javawebinar.basejava.model.Resume; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public abstract class AbstractStorageTest { + protected static final File STORAGE_DIR = Config.get().getStorageDir(); + + protected Storage storage; + + private static final String UUID_1 = UUID.randomUUID().toString(); + private static final String UUID_2 = UUID.randomUUID().toString(); + private static final String UUID_3 = UUID.randomUUID().toString(); + private static final String UUID_4 = UUID.randomUUID().toString(); + + private static final Resume R1; + private static final Resume R2; + private static final Resume R3; + private static final Resume R4; + + static { + R1 = new Resume(UUID_1, "Name1"); + R2 = new Resume(UUID_2, "Name2"); + R3 = new Resume(UUID_3, "Name3"); + R4 = new Resume(UUID_4, "Name4"); + + R1.addContact(ContactType.MAIL, "mail1@ya.ru"); + R1.addContact(ContactType.PHONE, "11111"); + + R4.addContact(ContactType.PHONE, "44444"); + R4.addContact(ContactType.SKYPE, "Skype"); +/* + R1.addSection(SectionType.OBJECTIVE, new TextSection("Objective1")); + R1.addSection(SectionType.PERSONAL, new TextSection("Personal data")); + R1.addSection(SectionType.ACHIEVEMENT, new ListSection("Achivment11", "Achivment12", "Achivment13")); + R1.addSection(SectionType.QUALIFICATIONS, new ListSection("Java", "SQL", "JavaScript")); + R1.addSection(SectionType.EXPERIENCE, + new OrganizationSection( + new Organization("Organization11", "http://Organization11.ru", + new Organization.Position(2005, Month.JANUARY, "position1", "content1"), + new Organization.Position(2001, Month.MARCH, 2005, Month.JANUARY, "position2", "content2")))); + R1.addSection(SectionType.EDUCATION, + new OrganizationSection( + new Organization("Institute", null, + new Organization.Position(1996, Month.JANUARY, 2000, Month.DECEMBER, "aspirant", null), + new Organization.Position(2001, Month.MARCH, 2005, Month.JANUARY, "student", "IT facultet")), + new Organization("Organization12", "http://Organization12.ru"))); + R2.addContact(ContactType.SKYPE, "skype2"); + R2.addContact(ContactType.PHONE, "22222"); + R1.addSection(SectionType.EXPERIENCE, + new OrganizationSection( + new Organization("Organization2", "http://Organization2.ru", + new Organization.Position(2015, Month.JANUARY, "position1", "content1")))); +*/ + } + + protected AbstractStorageTest(Storage storage) { + this.storage = storage; + } + + @Before + public void setUp() throws Exception { + storage.clear(); + storage.save(R1); + storage.save(R2); + storage.save(R3); + } + + @Test + public void size() throws Exception { + assertSize(3); + } + + @Test + public void clear() throws Exception { + storage.clear(); + assertSize(0); + } + + @Test + public void update() throws Exception { + Resume newResume = new Resume(UUID_1, "New Name"); + newResume.addContact(ContactType.MAIL, "mail1@google.com"); + newResume.addContact(ContactType.SKYPE, "NewSkype"); + newResume.addContact(ContactType.MOBILE, "+7 921 222-22-22"); + storage.update(newResume); + assertTrue(newResume.equals(storage.get(UUID_1))); + } + + @Test(expected = NotExistStorageException.class) + public void updateNotExist() throws Exception { + storage.get("dummy"); + } + + @Test + public void getAllSorted() throws Exception { + List list = storage.getAllSorted(); + assertEquals(3, list.size()); + List sortedResumes = Arrays.asList(R1, R2, R3); + Collections.sort(sortedResumes); + assertEquals(sortedResumes, list); + } + + @Test + public void save() throws Exception { + storage.save(R4); + assertSize(4); + assertGet(R4); + } + + @Test(expected = ExistStorageException.class) + public void saveExist() throws Exception { + storage.save(R1); + } + + @Test(expected = NotExistStorageException.class) + public void delete() throws Exception { + storage.delete(UUID_1); + assertSize(2); + storage.get(UUID_1); + } + + @Test(expected = NotExistStorageException.class) + public void deleteNotExist() throws Exception { + storage.delete("dummy"); + } + + @Test + public void get() throws Exception { + assertGet(R1); + assertGet(R2); + assertGet(R3); + } + + @Test(expected = NotExistStorageException.class) + public void getNotExist() throws Exception { + storage.get("dummy"); + } + + private void assertGet(Resume r) { + assertEquals(r, storage.get(r.getUuid())); + } + + private void assertSize(int size) { + assertEquals(size, storage.size()); + } +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/AllStorageTest.java b/test/ru/javawebinar/basejava/storage/AllStorageTest.java new file mode 100644 index 00000000..caa51dcc --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/AllStorageTest.java @@ -0,0 +1,22 @@ +package ru.javawebinar.basejava.storage; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses( + { + ArrayStorageTest.class, + SortedArrayStorageTest.class, + ListStorageTest.class, + MapUuidStorageTest.class, + MapResumeStorageTest.class, + ObjectFileStorageTest.class, + ObjectPathStorageTest.class, + XmlPathStorageTest.class, + JsonPathStorageTest.class, + DataPathStorageTest.class, + SqlStorageTest.class + }) +public class AllStorageTest { +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/ArrayStorageTest.java b/test/ru/javawebinar/basejava/storage/ArrayStorageTest.java new file mode 100644 index 00000000..c5903eed --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/ArrayStorageTest.java @@ -0,0 +1,9 @@ +package ru.javawebinar.basejava.storage; + +public class ArrayStorageTest extends AbstractArrayStorageTest { + + public ArrayStorageTest() { + super(new ArrayStorage()); + } + +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/DataPathStorageTest.java b/test/ru/javawebinar/basejava/storage/DataPathStorageTest.java new file mode 100644 index 00000000..f895fc44 --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/DataPathStorageTest.java @@ -0,0 +1,11 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.storage.serializer.DataStreamSerializer; + +public class DataPathStorageTest extends AbstractStorageTest { + + public DataPathStorageTest() { + + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new DataStreamSerializer())); + } +} diff --git a/test/ru/javawebinar/basejava/storage/JsonPathStorageTest.java b/test/ru/javawebinar/basejava/storage/JsonPathStorageTest.java new file mode 100644 index 00000000..a43d57b8 --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/JsonPathStorageTest.java @@ -0,0 +1,11 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.storage.serializer.JsonStreamSerializer; + +public class JsonPathStorageTest extends AbstractStorageTest { + + public JsonPathStorageTest() { + + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new JsonStreamSerializer())); + } +} diff --git a/test/ru/javawebinar/basejava/storage/ListStorageTest.java b/test/ru/javawebinar/basejava/storage/ListStorageTest.java new file mode 100644 index 00000000..07ae9d22 --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/ListStorageTest.java @@ -0,0 +1,8 @@ +package ru.javawebinar.basejava.storage; + +public class ListStorageTest extends AbstractStorageTest { + + public ListStorageTest() { + super(new ListStorage()); + } +} \ No newline at end of file diff --git a/src/MainTestArrayStorage.java b/test/ru/javawebinar/basejava/storage/MainTestArrayStorage.java similarity index 58% rename from src/MainTestArrayStorage.java rename to test/ru/javawebinar/basejava/storage/MainTestArrayStorage.java index b15b81e2..de489cb0 100644 --- a/src/MainTestArrayStorage.java +++ b/test/ru/javawebinar/basejava/storage/MainTestArrayStorage.java @@ -1,28 +1,30 @@ +package ru.javawebinar.basejava; + +import ru.javawebinar.basejava.model.Resume; +import ru.javawebinar.basejava.storage.ArrayStorage; + /** - * Test for your ArrayStorage implementation + * Test ru.javawebinar.basejava.storage.ArrayStorage */ 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"; + Resume r1 = new Resume("uuid1"); + Resume r2 = new Resume("uuid2"); + Resume r3 = new Resume("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("Get r1: " + ARRAY_STORAGE.get(r1.getUuid())); System.out.println("Size: " + ARRAY_STORAGE.size()); System.out.println("Get dummy: " + ARRAY_STORAGE.get("dummy")); printAll(); - ARRAY_STORAGE.delete(r1.uuid); + ARRAY_STORAGE.delete(r1.getUuid()); printAll(); ARRAY_STORAGE.clear(); printAll(); @@ -32,8 +34,8 @@ public static void main(String[] args) { static void printAll() { System.out.println("\nGet All"); - for (Resume r : ARRAY_STORAGE.getAll()) { + for (Resume r : ARRAY_STORAGE.getAllSorted()) { System.out.println(r); } } -} +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/MapResumeStorageTest.java b/test/ru/javawebinar/basejava/storage/MapResumeStorageTest.java new file mode 100644 index 00000000..321aa46e --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/MapResumeStorageTest.java @@ -0,0 +1,8 @@ +package ru.javawebinar.basejava.storage; + +public class MapResumeStorageTest extends AbstractStorageTest { + + public MapResumeStorageTest() { + super(new MapResumeStorage()); + } +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/MapUuidStorageTest.java b/test/ru/javawebinar/basejava/storage/MapUuidStorageTest.java new file mode 100644 index 00000000..556dc591 --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/MapUuidStorageTest.java @@ -0,0 +1,8 @@ +package ru.javawebinar.basejava.storage; + +public class MapUuidStorageTest extends AbstractStorageTest { + + public MapUuidStorageTest() { + super(new MapUuidStorage()); + } +} diff --git a/test/ru/javawebinar/basejava/storage/ObjectFileStorageTest.java b/test/ru/javawebinar/basejava/storage/ObjectFileStorageTest.java new file mode 100644 index 00000000..9994f4bf --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/ObjectFileStorageTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.storage.serializer.ObjectStreamSerializer; + +public class ObjectFileStorageTest extends AbstractStorageTest { + + public ObjectFileStorageTest() { + super(new FileStorage(STORAGE_DIR, new ObjectStreamSerializer())); + } +} diff --git a/test/ru/javawebinar/basejava/storage/ObjectPathStorageTest.java b/test/ru/javawebinar/basejava/storage/ObjectPathStorageTest.java new file mode 100644 index 00000000..b25fc71a --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/ObjectPathStorageTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.storage.serializer.ObjectStreamSerializer; + +public class ObjectPathStorageTest extends AbstractStorageTest { + + public ObjectPathStorageTest() { + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new ObjectStreamSerializer())); + } +} diff --git a/test/ru/javawebinar/basejava/storage/SortedArrayStorageTest.java b/test/ru/javawebinar/basejava/storage/SortedArrayStorageTest.java new file mode 100644 index 00000000..6720a801 --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/SortedArrayStorageTest.java @@ -0,0 +1,8 @@ +package ru.javawebinar.basejava.storage; + +public class SortedArrayStorageTest extends AbstractArrayStorageTest { + + public SortedArrayStorageTest() { + super(new SortedArrayStorage()); + } +} \ No newline at end of file diff --git a/test/ru/javawebinar/basejava/storage/SqlStorageTest.java b/test/ru/javawebinar/basejava/storage/SqlStorageTest.java new file mode 100644 index 00000000..afc89c0d --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/SqlStorageTest.java @@ -0,0 +1,14 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.Config; + +/** + * gkislin + * 23.06.2016 + */ +public class SqlStorageTest extends AbstractStorageTest { + + public SqlStorageTest() { + super(Config.get().getStorage()); + } +} diff --git a/test/ru/javawebinar/basejava/storage/XmlPathStorageTest.java b/test/ru/javawebinar/basejava/storage/XmlPathStorageTest.java new file mode 100644 index 00000000..6b522ded --- /dev/null +++ b/test/ru/javawebinar/basejava/storage/XmlPathStorageTest.java @@ -0,0 +1,11 @@ +package ru.javawebinar.basejava.storage; + +import ru.javawebinar.basejava.storage.serializer.XmlStreamSerializer; + +public class XmlPathStorageTest extends AbstractStorageTest { + + public XmlPathStorageTest() { + + super(new PathStorage(STORAGE_DIR.getAbsolutePath(), new XmlStreamSerializer())); + } +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 00000000..b1bef4a3 --- /dev/null +++ b/web/index.html @@ -0,0 +1,15 @@ + + + + + + Курс JavaSE + Web. + + +
Приложение вебинара Практика Java. Разработка Web + приложения."
+

Курс JavaSE + Web

+ + + \ No newline at end of file diff --git a/web/style.css b/web/style.css new file mode 100644 index 00000000..bf3fe119 --- /dev/null +++ b/web/style.css @@ -0,0 +1,14 @@ +header { + background: none repeat scroll 0 0 #A6C9E2; + color: #2E6E9E; + font-size: 20px; + padding: 5px 20px; +} + +footer { + background: none repeat scroll 0 0 #A6C9E2; + color: #2E6E9E; + font-size: 20px; + padding: 5px 20px; + margin: 20px 0; +} \ No newline at end of file diff --git a/web/test.html b/web/test.html new file mode 100644 index 00000000..9830809c --- /dev/null +++ b/web/test.html @@ -0,0 +1,10 @@ + + + + + Title + + +Test + + \ No newline at end of file