Вы находитесь на странице: 1из 39

Санкт-Петербургский Государственный Политехнический Университет

Институт информационных технологий и управления


Кафедра Компьютерных Систем и Программных Технологий

Курсовой проект
по дисциплине
Программирование на Java
Тема: Отдел кадров

Работа защищена с оценкой_______________


«___»______________20____г.
Научный руководитель___________________
(подпись)

Выполнил:

студент группы_____________________________________________________
(номер группы) (подпись) (ФИО)

Научный руководитель:

__________________________________________________________________
(ученая степень, звание, ФИО) (подпись) (ФИО)

Санкт-Петербург
Оглавление
 Техническое задание.........................................3
 Метод решения..................................................4
 Функционально-файловая структура..............7
 Листинг:
 Employee.java................................8
 Employees.java...............................10
 Education.java................................12
 Degree.java.....................................12
 State.java.........................................14
 Type.java.........................................14
 Passport.java...................................15
 Address.java....................................16
 Name.java........................................17
 Series.java........................................19
 Position.java.....................................20
 Departament.java..............................21

 CLIManager.java..............................22

 CommandHandler.java......................25

 StdinReader.java................................31

 Main.java............................................38

 Коды ошибок......................................................40

2
Техническое задание

Написать программу, реализующую логику отдела кадров. Данный


программный продукт будет:
1. Обеспечивать корректировку баз данных.

Осуществлять поиск по критериям.


Общие положения
Отдел - Приставка: от-; корень: -дел- сравнительно автономная часть какой-либо
структуры.

Кадр - Происходит от франц. cadre «оправа, рамка; личный состав»

Функциональные требования

Дать HR-менеджеру возможность:


Просматривать список работников (Сортировка: отдел -> имя)
Просматривать детальные данные о конкретном работнике
Добавлять
Увольнять
Возвращать / Оправлять в отпуск
Редактировать
Искать (по отделу, имени, табельному номеру, названию должности, можно
комбинировать)

3
Специальные требования

Язык реализации - Java 1.5+ (Наличие коллекций)

QL БД, работа через JDBC (Java Database Connectivity)

Метод решения
Язык - Java 1.8
SQL-подобная БД - MySQL

Внешние зависимости:
MySQL JDBC Connector - Driver для базы данных Gradle: group: 'mysql', name:
'mysql-connector-java', version: ‘6.0.5'

GSON - библиотека от Google для конвертации объектов в JSON и vice-versa


Gradle: group: 'com.google.code.gson', name: 'gson', version: ‘2.8.0'

JOpt Simple - парсер stdin


Gradle: group: 'net.sf.jopt-simple', name: 'jopt-simple', version: '6.0-alpha-1'

Финальная архитектура

4
Структура базы данных

Все поля класса Employee хранятся в базе данных в виде JSON объектов.
Пользователь вводит команды и опции к ним (описано в help), класс
CommandHandler их обрабатывает и исполняет, если это возможно.
Ввод идет до команды Quit или же до одной из критических ошибок
(Проблемы с БД / файлом конфигурации). SQLDAO требует наличие
в файле конфигурации следующих данных:
1. Host базы данных со всеми флагами подключения
2. Логин
3. Пароль
5
4. Название таблицы
5. Схема таблицы

Функционально-файловая структура

6
Листинг

Employee.java

7
package HR.BL;

import HR.BL.employeeInf.Education;
import HR.BL.employeeInf.Passport;
import HR.BL.employeeInf.Position;
import HR.IO.StringDesigner;

import java.time.LocalDate;

public class Employee {


Integer clockNumber;
Passport passport;
Position position;
Education education;

LocalDate employment;

public Employee() {

public Employee(int clockNumber, Passport passport, Position position,


Education education, LocalDate employment) {
this.clockNumber = clockNumber;
this.passport = passport;
this.position = position;
this.education = education;
this.employment = employment;
}

public Integer getClockNumber() {


return clockNumber;
}

public void setClockNumber(Integer clockNumber) {


this.clockNumber = clockNumber;
}

public Passport getPassport() {


return passport;
}

public void setPassport(Passport passport) {


this.passport = passport;
}

public Position getPosition() {


return position;
}

public void setPosition(Position position) {


this.position = position;
}

public Education getEducation() {


return education;
}

8
public void setEducation(Education education) {
this.education = education;
}

public LocalDate getEmployment() {


return employment;
}

public void setEmployment(LocalDate employment) {


this.employment = employment;
}

@Override
public String toString() {
return StringDesigner.toString("\n", false, "#" + clockNumber,
position.toString(), passport.toString(), education);
}
}

Employees.java

package HR.BL;

import HR.BL.employeeInf.positionInf.Department;
import HR.BL.employeeInf.positionInf.EmplState;

9
import java.util.*;

public class Employees extends HashMap<Department, List<Employee>> {


Comparator<Employee> nameComp = Comparator.comparing(empl ->
empl.getPassport().getName().toString());

public void add(Employee employee) {


Department dep = employee.getPosition().getDepartment();
if (!containsKey(dep)) {
put(dep, new ArrayList<>());
}

get(dep).add(employee);
}

@Override
public List<Employee> get(Object key) {
List<Employee> res = super.get(key);
res.sort(nameComp);
return res;
}

public Employees getByState(EmplState state) {


Employees res = new Employees();
for (Map.Entry<Department, List<Employee>> dep : entrySet()) {
for (Employee employee : dep.getValue()) {
if (employee.getPosition().getState() == state)
res.add(employee);
}
}

return res;
}

public Employee getByClockNumber(int clockNumber) {


Employee res = null;
Iterator<Map.Entry<Department, List<Employee>>> iterator =
entrySet().iterator();
while (iterator.hasNext()) {
List<Employee> withinDep = iterator.next().getValue();
for (Employee employee : withinDep) {
if (clockNumber == employee.getClockNumber()) {
res = employee;
break;
}
}
}

return res;
}

public List<Employee> getAsList() {


List<Employee> res = new ArrayList<>();
forEach(((department, employees) -> res.addAll(employees)));

return res;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();

10
forEach((dep, list) -> {
builder.append(dep + ":\n");

list.stream()
.sorted(nameComp)
.forEach(empl -> builder.append(empl.getClockNumber() +
". " + empl.getPassport().getName() + "\n"));
});

return builder.toString().replaceAll("\n$", "");


}
}

Education.java
package HR.BL.employeeInf;

import HR.BL.employeeInf.educationInf.EduRecord;

import java.util.ArrayList;

public class Education extends ArrayList<EduRecord> {

11
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Education:\n");
for (EduRecord record : this) {
stringBuilder.append("\t" + (1 + indexOf(record)) + ". " + record +
"\n");
}

return stringBuilder.toString();
}
}
Degree.java
package HR.BL.employeeInf.educationInf;

public enum Degree {


STUDENT,
BACHELOR,
MASTER,
DOCTOR
}

EduRecord.java
package HR.BL.employeeInf.educationInf;

import java.time.LocalDate;

public class EduRecord {


Type type;
State state;
Degree degree;

String institutionTitle;
12
LocalDate participation;
LocalDate graduation;

Long specCode;
String specTitle;
String certificationID;

public EduRecord() {

public EduRecord(Type type, State state, String institutionTitle, LocalDate


participation, LocalDate graduation) {
this.type = type;
this.state = state;
this.institutionTitle = institutionTitle;
this.participation = participation;
this.graduation = graduation;
}

public Type getType() {


return type;
}

public void setType(Type type) {


this.type = type;
}

public State getState() {


return state;
}

public void setState(State state) {


this.state = state;
}

public Degree getDegree() {


return degree;
}

public void setDegree(Degree degree) {


this.degree = degree;
}

public String getInstitutionTitle() {


return institutionTitle;
}

public void setInstitutionTitle(String institutionTitle) {


this.institutionTitle = institutionTitle;
}

public LocalDate getParticipation() {


return participation;
}

public void setParticipation(LocalDate participation) {


this.participation = participation;
}

public LocalDate getGraduation() {


return graduation;
}

13
public void setGraduation(LocalDate graduation) {
this.graduation = graduation;
}

public Long getSpecCode() {


return specCode;
}

public String getSpecTitle() {


return specTitle;
}

public String getCertificationID() {


return certificationID;
}

public void setCertificationID(String certificationID) {


this.certificationID = certificationID;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();

String degree_string = degree == null ? "" : "AS " + degree;


String cert_string = certificationID == null ? "" : " CERTIFICATE #" +
certificationID;
String graduation_string = graduation == null ? "NOW" :
graduation.toString();
builder.append(String.format("%s %s %s IN %s FROM %s TILL %s %s"
, type, state, degree_string, institutionTitle,
participation.toString(), graduation_string, cert_string));

return builder.toString();

}
}
State.java
package HR.BL.employeeInf.educationInf;

public enum State {


COMPLETED,
INCOMPLETED,
IN_PROGRESS
}
Type.java
package HR.BL.employeeInf.educationInf;

public enum Type {


GENERAL,
POST_SECONDARY,
HIGHER,
ADDITIONAL
}

14
Passport.java
package HR.BL.employeeInf;

import HR.BL.employeeInf.passportInf.Address;
import HR.BL.employeeInf.passportInf.Name;
import HR.BL.employeeInf.passportInf.Series;

import java.time.LocalDate;

public class Passport {


Integer PID;
Series series;

Name name;
Address address;
LocalDate birth;

public Passport(int PID, Series series, Name name, Address address,


LocalDate birth) {
this.PID = PID;
this.series = series;
this.name = name;
this.address = address;
this.birth = birth;
}

15
public Integer getPID() {
return PID;
}

public void setPID(Integer PID) {


this.PID = PID;
}

public Series getSeries() {


return series;
}

public void setSeries(Series series) {


this.series = series;
}

public Name getName() {


return name;
}

public void setName(Name name) {


this.name = name;
}

public Address getAddress() {


return address;
}

public void setAddress(Address address) {


this.address = address;
}

public LocalDate getBirth() {


return birth;
}

public void setBirth(LocalDate birth) {


this.birth = birth;
}

@Override
public String toString() {
return "PIN: " + series + " " + PID +
"\nName: " + name +
"\nAddress: " + address +
"\nBirth date: " + birth;
}

}
Address.java
package HR.BL.employeeInf.passportInf;

import HR.IO.StringDesigner;

public class Address {


String street;
String town;
String region;
String country;
Integer postIndex;

16
public Address() {

public Address(String street, String town, String region, String country,


int postIndex) {
this.street = street;
this.town = town;
this.region = region;
this.country = country;
this.postIndex = postIndex;
}

public String getStreet() {


return street;
}

public void setStreet(String street) {


this.street = street;
}

public String getTown() {


return town;
}

public void setTown(String town) {


this.town = town;
}

public String getRegion() {


return region;
}

public void setRegion(String region) {


this.region = region;
}

public String getCountry() {


return country;
}

public void setCountry(String country) {


this.country = country;
}

public Integer getPostIndex() {


return postIndex;
}

public void setPostIndex(Integer postIndex) {


this.postIndex = postIndex;
}

@Override
public String toString() {
return StringDesigner.toString(" ", false, street, town, region,
country, postIndex);
}
}

17
Name.java
package HR.BL.employeeInf.passportInf;

import HR.IO.StringDesigner;

public class Name {


String first;
String last;
String patronymic;

public Name() {

public Name(String first, String last, String patronymic) {


this.first = first;
this.last = last;
this.patronymic = patronymic;
}

public String getFirst() {


return first;
}

public String getLast() {


return last;
}

public String getPatronymic() {


return patronymic;
}

public void setFirst(String first) {


this.first = first;
}

public void setLast(String last) {


this.last = last;
}

public void setPatronymic(String patronymic) {


this.patronymic = patronymic;
}

@Override
public String toString() {
return StringDesigner.toString(" ", false, first, last, patronymic);
}
}

Series.java
package HR.BL.employeeInf.passportInf;

import HR.IO.StringDesigner;

18
public class Series {
int regionCode;
int issuanceYear;

public Series() {

public Series(int regionCode, int issuanceYear) {


this.regionCode = regionCode;
this.issuanceYear = issuanceYear;
}

public int getRegionCode() {


return regionCode;
}

public void setRegionCode(int regionCode) {


this.regionCode = regionCode;
}

public int getIssuanceYear() {


return issuanceYear;
}

public void setIssuanceYear(int issuanceYear) {


this.issuanceYear = issuanceYear;
}

@Override
public String toString() {
return StringDesigner.toString(" ", false, regionCode, issuanceYear);
}
}

Position.java
package HR.BL.employeeInf;

import HR.BL.employeeInf.positionInf.Department;
import HR.BL.employeeInf.positionInf.EmplState;

public class Position {


int id;
EmplState state;
Department department;
String title;
long salary;

public Position() {

public Position(int id, EmplState emplState, Department department, String


title, long salary) {
19
this.id = id;
this.state = emplState;
this.department = department;
this.title = title;
this.salary = salary;
}

public int getId() {


return id;
}

public void setId(int id) {


this.id = id;
}

public EmplState getState() {


return state;
}

public void setState(EmplState state) {


this.state = state;
}

public Department getDepartment() {


return department;
}

public void setDepartment(Department department) {


this.department = department;
}

public String getTitle() {


return title;
}

public void setTitle(String title) {


this.title = title;
}

public long getSalary() {


return salary;
}

public void setSalary(long salary) {


this.salary = salary;
}

@Override
public String toString() {
return "ID: " + id +
"\nStatus: " + state +
"\nDepartment: " + department +
"\nTitle: " + title +
"\nSalary: " + salary;
}
}

Departament.java
package HR.BL.employeeInf.positionInf;
20
public enum Department {
HUMAN_RESOURCES,
PRODUCTION,
ADVERTISING,
FINENCIAL,
LEGAL,
PURCHASING,
SALES,
RESEARCH,
OTHER
}

EmplState.java
package HR.BL.employeeInf.positionInf;

public enum EmplState {


FIRED,
ACTIVE,
ON_VACATION
}

CLIManager.java
package HR.CLI;

import HR.BL.Employee;
import HR.BL.Employees;
import HR.BL.employeeInf.educationInf.State;
import HR.BL.employeeInf.passportInf.Name;
import HR.BL.employeeInf.positionInf.Department;
import HR.BL.employeeInf.positionInf.EmplState;
import HR.dataModel.EmployeeDAO;

import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class CLIManager {


EmployeeDAO DAO;

public CLIManager(EmployeeDAO DAO) {


this.DAO = DAO;
}

21
public Employees getEmployees() {
return DAO.getEmployees();
}

public Employees find() {


return null;
}

public void add(Employee e) {


DAO.addEmployee(e);
}

public void del(int clockNum) {


DAO.deleteEmployee(clockNum);
}

public boolean editState(int clockNumber, EmplState state) {


Employee inBase = DAO.getEmployees().getByClockNumber(clockNumber);
boolean res = inBase != null ? true : false;
if (res) {
DAO.deleteEmployee(clockNumber);

inBase.getPosition().setState(state);
DAO.addEmployee(inBase);
}

return res;
}

public int getLastID() {


int lindex = 0;
Employees employees = DAO.getEmployees();

Iterator<Map.Entry<Department, List<Employee>>> iterator =


employees.entrySet().iterator();
while (iterator.hasNext()) {
List<Employee> withinDep = iterator.next().getValue();
for (Employee employee : withinDep) {
if (employee.getClockNumber() > lindex)
lindex = employee.getClockNumber();
}
}

return lindex;
}

CLine.java
package HR.CLI;

import joptsimple.OptionSet;

public class CLine {


Command command;
OptionSet optionSet;

public CLine(String line) {


String command_string = line.split("\\s+")[0];
22
for (Enum e : Command.values()) {
if (e.name().equalsIgnoreCase(command_string)) {
this.command = (Command) e;
}
}

this.optionSet = CommandLineParser.parse(line);
}

public boolean isValid() {


return command != null ? true : false;
}

public Command getCommand() {


return command;
}

public OptionSet getOptionSet() {


return optionSet;
}
}

Command.java
package HR.CLI;

public enum Command {


ADD,
FIRE,
VACATION,
SET_ACTIVE,
EDIT,
SHOW,
QUIT,
FIND,
DESCRIBE,
HELP
}

CommandHandler.java
package HR.CLI;

import HR.IO.*;
import joptsimple.*;
import HR.BL.Employee;
import HR.BL.Employees;
import HR.BL.employeeInf.*;
import HR.BL.employeeInf.passportInf.*;
import HR.BL.employeeInf.positionInf.*;
import HR.BL.employeeInf.educationInf.*;

23
import java.time.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;
import java.util.function.*;

import static HR.CLI.Command.*;


import static java.lang.System.*;

public class CommandHandler {


CLIManager manager;

public CommandHandler(CLIManager manager) {


this.manager = manager;
}

public void handle(CLine cLine) {


if (!cLine.isValid()) {
throw new IllegalArgumentException("Wrong command");
}

OptionSet opt = cLine.getOptionSet();


Command command = cLine.getCommand();

Integer clockNum = null;


if (opt.has("id")) {
try {
clockNum = Integer.parseInt(String.valueOf(opt.valueOf("id")));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("^Seems not to be clock
number");
}
}

if (clockNum == null && (command == EDIT || command == VACATION ||


command == SET_ACTIVE || command == FIRE
|| command == DESCRIBE)) {
throw new IllegalArgumentException("^You've forgotten clock
number");
} else if (command == FIND && (!opt.has("d") && !opt.has("n") && !
opt.has("p") && !opt.has("id"))) {
throw new IllegalArgumentException("Find what?");
}

switch (command) {
case ADD:
add();
break;
case EDIT:
edit(clockNum);
break;
case FIRE:
fire(clockNum);
break;
case SET_ACTIVE:
setActive(clockNum);
break;
case VACATION:
vacation(clockNum);
break;
case SHOW:

24
boolean fired = opt.has("f") ? true : false;
show(fired);
break;
case FIND:
find(opt);
break;
case DESCRIBE:
describe(clockNum);
break;
case HELP:
help();
break;
case QUIT:
out.println("Bye");
exit(0);
}
}

void show(boolean fired) {


Employees employees = manager.getEmployees();
if (fired) {
Employees firedEmpl = employees.getByState(EmplState.FIRED);
if (firedEmpl.isEmpty()) {
out.println("There is no fired employees, usually we kill em");
} else out.println(firedEmpl);
} else out.println(employees.getByState(EmplState.ACTIVE));
}

void help() {
StringBuilder help_str = new StringBuilder();
help_str.append("***HELP***");
help_str.append("\nModifying:" +
"\n\tADD" +
"\n\tEDIT -id <clockNumber>" +
"\nChanges employee's state to -> <state>:" +
"\n\tFIRE -id <clockNumber> -> <FIRED>" +
"\n\tVACATION -id <clockNumber> -> <ON_VACATION>" +
"\n\tSET_ACTIVE -id <clockNumber> -> <ACTIVE>" +
"\nDisplaying:" +
"\n\tSHOW -f - shows all contacts from database except fired or
only fired with -f flag" +
"\n\tFIND -n <name> -p <position> -id <clockNumber> -d
<department> - parametrized search, parameters" +
"\n\t\t may be placed in any order, each of them is optional" +
"\n\tDESCRIBE -id <clockNumber> - shows all employee
information" +
"\nOther:" +
"\nHELP - prints help" +
"\nQUIT - quits the program" +
"\n***HELP END***");

out.println(help_str);
}

Employee emplFromStdin(boolean edit, int cn) {


StdinReader r = new StdinReader();

Passport passport;
passport: {
Series pSeries = (Series) r.readObj("Passport series",
"\\d{2}\\s+\\d{2}", Series.class);
int PIN = r.readInt("Passport ID");

25
Name name = (Name) r.readObj("Name", "['\\w]{1,45}\\s+['\\w]
{1,53}\\s+(['\\w]+)?", Name.class);

String street = r.read("Street", "['/\\s\\w\\d-_(),]+");


String town = r.read("Town", "['/\\s\\w\\d-_(),]+");
String region = r.read("Region", "['/\\s\\w\\d-_(),]+", false);
String country = r.read("Country", "['/\\s\\w\\d-_(),]+");
Integer postIndex = r.readInt("Post index");

Address address = new Address(street, town, region, country,


postIndex);
LocalDate birth = r.readDate("Birth date");

passport = new Passport(PIN, pSeries, name, address, birth);


}

Position position;
position: {
int id = r.readInt("Position ID");
Department department = (Department) r.read("Department",
Department.values());
String title = r.read("Position title", "['/\\s\\w\\d-_(),]+");
Long salary = r.readLong("Salary");

position = new Position(id, EmplState.ACTIVE, department, title,


salary);
}

Education eduRecords = new Education();


education: {
while (true) {
String req = r.read("Wanna add some educational record? [Y/N]",
"(?i)Y|N");
if (req.equalsIgnoreCase("N")) {
if (eduRecords.isEmpty()) {
out.println("JK, you've got no choice!");
} else break;
}

Type type = (Type) r.read("Type", Type.values());


State state = (State) r.read("State", State.values());
String place = r.read("Institution title", ".+");
LocalDate participation = r.readDate("Participated");
LocalDate graduation = state == State.IN_PROGRESS || state ==
State.INCOMPLETED ? null : r.readDate("Graduated");

EduRecord record = new EduRecord(type, state, place,


participation, graduation);

Degree degree;
if (type == Type.HIGHER) {
if (state != State.INCOMPLETED) {
degree = (Degree) r.read("Degree", Degree.values());
} else degree = Degree.STUDENT;

record.setDegree(degree);
}

String certificated = r.read("Certificate? [Y/N]", "(?i)Y|N");


if (certificated.equalsIgnoreCase("Y")) {
String certID = r.read("CertificationID", "['-/\\s\\w\\d]

26
+");
record.setCertificationID(certID);
}

eduRecords.add(record);
}
}

Employee employee;
employee: {
Integer clockNum = cn;
if (!edit) {
clockNum = manager.getLastID() + 1;
}

LocalDate empl = r.readDate("Employment date");


employee = new Employee(clockNum, passport, position, eduRecords,
empl);
}

return employee;
}

Employee emplFromStdin() {
return emplFromStdin(false, 12345);
}

void describe(int clockNum) {


out.println(manager.getEmployees().getByClockNumber(clockNum));
}

void find(OptionSet opt) {


Department dep = null;
if (opt.has("d")) {
boolean validDep = false;
String dep_string = (String) opt.valueOf("d");
for (Enum e : Department.values()) {
if (dep_string.equalsIgnoreCase(e.name())) {
dep = (Department) e;
validDep = true;
break;
}
}

if (!validDep) throw new IllegalArgumentException("There is no " +


dep_string + " department");
}

Integer clockNum = null;


if (opt.has("id")) {
try {
clockNum = Integer.parseInt(String.valueOf(opt.valueOf("id")));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Wrong clock number");
}
}

String name = opt.has("n") ? (String) opt.valueOf("n") : null;


String pos = opt.has("p") ? (String) opt.valueOf("p") : null;

List<Employee> employeeList =
opt.has("d") ? manager.getEmployees().get(dep) :

27
manager.getEmployees().getAsList();

if (clockNum == null && pos == null && name == null) {


Employees employees = new Employees();
employeeList.forEach(employees::add);
out.println(employees);
return;
}

// F ~ Filter

Predicate<Employee> nameF = employee -> {


String name_str = employee.getPassport().getName().toString();

Pattern pattern = Pattern.compile(name, Pattern.CASE_INSENSITIVE);


Matcher matcher = pattern.matcher(name_str);

return matcher.find() ? true : false;


};

Predicate<Employee> posF = employee -> {


String pos_str = employee.getPosition().getTitle();

Pattern pattern = Pattern.compile(pos, Pattern.CASE_INSENSITIVE);


Matcher matcher = pattern.matcher(pos_str);

return matcher.find() ? true : false;


};

Integer finalClockNum = clockNum;


Predicate<Employee> idF = employee -> employee.getClockNumber() ==
finalClockNum ? true : false;

if (name == null) {
nameF = null;
}

if (pos == null) {
posF = null;
}

if (clockNum == null) {
idF = null;
}

List<Predicate<Employee>> predicates =
Arrays.asList(nameF, posF, idF).stream()
.filter(p -> p != null)
.collect(Collectors.toList());

for (Predicate<Employee> predicate : predicates) {


employeeList.removeIf(predicate.negate());
}

Employees employees = new Employees();


employeeList.forEach(employees::add);
out.println(employees);
}

void add() {
Employee employee = emplFromStdin();
manager.add(employee);
out.println("Succeed");

28
}

void edit(int clockNum) {


Employee employee = emplFromStdin(true, clockNum);
manager.del(clockNum);
manager.add(employee);
}

void fire(int clockNum) {


out.println(manager.editState(clockNum, EmplState.FIRED) ? "Succeed" :
"There is no such employee");
}

void setActive(int clockNum) {


out.println(manager.editState(clockNum, EmplState.ACTIVE) ? "Succeed" :
"There is no such employee");
}

void vacation(int clockNum) {


out.println(manager.editState(clockNum, EmplState.ON_VACATION) ?
"Succeed" : "There is no such employee");
}
}

CommandLineParser.java

package HR.CLI;

import joptsimple.*;

public class CommandLineParser {


public static OptionSet parse(String line) {
String[] parts = line.split("\\s+");
OptionParser parser = new OptionParser() {
{
accepts("n").withRequiredArg();
accepts("p").withRequiredArg();
accepts("id").withRequiredArg();
accepts("d").withRequiredArg();
accepts("f");
}
};

OptionSet opts;
try {
opts = parser.parse(parts);
} catch (joptsimple.OptionException |
joptsimple.ValueConversionException e) {
throw new IllegalArgumentException(e.getLocalizedMessage());
}

return opts;
}

29
}

StdinReader.java

package HR.IO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.function.Function;

import static java.lang.System.*;

public class StdinReader implements AutoCloseable {


BufferedReader reader;

{
this.reader = new BufferedReader(new InputStreamReader(System.in));
}

public String read(String annotation, String template, boolean appendNulls)


{
try {
while (true) {
out.print(annotation + ": ");
String str = reader.readLine();
if (str.matches(template))
return str;
else if (str.isEmpty() && appendNulls)
return null;
else out.println("Follow the template -> " + template);
}
} catch (IOException e) {
e.printStackTrace();
}

return null;
}

public String read(String annotation, String template) {


return read(annotation, template, false);

public long readLong(String annotation) {


return Long.parseLong(read(annotation, "\\d+"));
}

public int readInt(String annotation) {


return (int) readLong(annotation);
}

30
public int[] readIntArray(String annotation, String template, String
subdivider) {
while (true) {
int[] array;
String str = read(annotation, template);

try {
array = Arrays.stream(str.split(subdivider))
.mapToInt(Integer::parseInt)
.toArray();

return array;
} catch (NumberFormatException e) {
err.print("Nice try, again\n");
}
}
}

public LocalDate readDate(String annotation) {


LocalDate res;
while (true) {
int[] parts = readIntArray(annotation,
"\\d{1,2}\\s+\\d{1,2}\\s+\\d{4}", "\\s+");
try {
if (parts[2] > LocalDate.now().getYear()) {
err.print("^CYA in the future\n");
Thread.sleep(100);
continue;
} else if (parts[2] < 1940) {
err.print("Nah, you can't hire him, he'll die way too
soon!\n");
Thread.sleep(100);
continue;
}

res = LocalDate.of(parts[2], parts[1], parts[0]);


return res;
} catch (DateTimeException e) {
err.print("Nice try, again\n");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public Object readObj(String annotation, String template, Class type) {


Object res = null;
String str = read(annotation, template);
String[] parts = str.split("\\s+");

Constructor[] cnsts = type.getConstructors();


for (Constructor cnst : cnsts) {
if (cnst.getParameterCount() == parts.length) {
Object[] cnstParams = new Object[parts.length];
Class[] types = cnst.getParameterTypes();
for (int i = 0; i < types.length; i++) {
if (types[i] == Integer.class || types[i] == int.class) {
Integer integer = Integer.parseInt(parts[i]);
cnstParams[i] = integer;
} else if (types[i] == Long.class || types[i] == long.class)
{
Long l = Long.parseLong(parts[i]);
cnstParams[i] = l;

31
} else {
try {
cnstParams[i] = types[i].cast(parts[i]);
} catch (ClassCastException e) {
err.println("Call u'r programmer, it's definitely
not DIY time");
exit(1);
}
}
}

try {
res = cnst.newInstance(cnstParams);
} catch (InstantiationException | IllegalAccessException |
InvocationTargetException e) {
e.printStackTrace();
}
}
}

return res;
}

public Enum read(String annotation, Enum[] enumVals) {


Enum res = null;
Function<Enum[], String> enumToRegex = anEnum -> {
StringBuilder regexBuiler = new StringBuilder();
for (Enum e : anEnum) {
regexBuiler.append("(" + e + ")|");
}

return "(?i)" + regexBuiler.toString().replaceAll("|$", "");


};

String str = read(annotation, enumToRegex.apply(enumVals));


for (Enum e : enumVals) {
if (str.equalsIgnoreCase(e.name())) {
res = e;
}
}

return res;
}

@Override
public void close() {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

32
StringDesigner.java

package HR.IO;

public class StringDesigner {

@SafeVarargs
public static <T> String toString(String separator, boolean appendNulls,
T ... args) {
StringBuilder stringBuilder = new StringBuilder();
for (T arg : args) {
String param = String.valueOf(arg);

boolean isNull = param.equals("null") || param.equals("");


if (appendNulls && isNull) {
stringBuilder.append(separator);
continue;
} else if (isNull) {
continue;
}

stringBuilder.append(param + separator);
}

return stringBuilder.toString() // Getting rid of redundant separator at


the end of line
.replaceAll(separator + "$", "");
}
}

EmployeeDAO.java
package HR.dataModel;

import HR.BL.Employee;
import HR.BL.Employees;

public interface EmployeeDAO {


void addEmployee(Employee employee);
void deleteEmployee(int clockNum);
boolean isEmpty();
Employees getEmployees();
}

SQLDAO.java

package HR.dataModel;

import HR.BL.*;
import HR.BL.employeeInf.*;
import com.google.gson.*;

33
import java.io.*;
import java.sql.*;
import java.time.LocalDate;
import java.util.Properties;

import static java.lang.System.*;

public class SQLDAO implements EmployeeDAO {


String host;
String usr;
String pwd;

String tableTitle;
String tableScheme;

Properties conf = new Properties();


Gson gson = new Gson();

String create_table;
String add_empl;
String del_empl;
String select_all;
String set_encoding;

public SQLDAO(File config) {


try {
FileInputStream FIS = new FileInputStream(config);
conf.load(FIS);

host = conf.getProperty("DBHost");
usr = conf.getProperty("DBUser");
pwd = conf.getProperty("DBPwd");

tableTitle = conf.getProperty("tableTitle");
tableScheme = conf.getProperty("tableScheme");

create_table = "CREATE TABLE " + tableTitle + "(" + tableScheme +


")";
add_empl = "INSERT INTO " + tableTitle + " VALUES(?, ?, ?, ?, ?)";
del_empl = "DELETE FROM " + tableTitle + " WHERE id=?";
select_all = "SELECT * FROM " + tableTitle;
set_encoding = "SET NAMES UTF8";

try (Connection con = DriverManager.getConnection(host, usr, pwd)) {


DatabaseMetaData md = con.getMetaData();
ResultSet tables = md.getTables(null, tableScheme, tableTitle,
new String[] {"TABLE"});
if (!tables.next()) {
Statement stmt = con.createStatement();
stmt.executeUpdate(create_table);
err.println("There was no " + tableTitle + " table, so we've
created it...\n");
}
} catch (SQLException e) {
err.println("Seems like there is no access to database ^_^");
exit(70);
}

} catch (IOException e) {
e.printStackTrace();
}
}

34
@Override
public Employees getEmployees() {
Employees employees = new Employees();
try (Connection con = DriverManager.getConnection(host, usr, pwd)) {
Statement stmt = con.createStatement();
ResultSet res = stmt.executeQuery(select_all);

JsonParser p = new JsonParser();


while (res.next()) {
Integer clockNumber = res.getInt("id");
Passport passport =
gson.fromJson(p.parse(res.getString("pspt")), Passport.class);
Position position = gson.fromJson(p.parse(res.getString("pos")),
Position.class);
Education education =
gson.fromJson(p.parse(res.getString("edu")), Education.class);
LocalDate emplDate =
gson.fromJson(p.parse(res.getString("emplDate")), LocalDate.class);

Employee employee = new Employee(clockNumber, passport,


position, education, emplDate);
employees.add(employee);
}
} catch (SQLException e) {
err.println("Seems like there is no access to database ^_^");
exit(70);
}

return employees;
}

@Override
public void addEmployee(Employee employee) {
try (Connection con = DriverManager.getConnection(host, usr, pwd)) {
DatabaseMetaData metaData = con.getMetaData();
ResultSet tables = metaData.getTables(null, tableScheme, tableTitle,
null);

boolean hasConfTable = tables.next();


if (!hasConfTable) {
Statement stmt = con.createStatement();
stmt.executeUpdate(create_table);
}
Statement stmt = con.createStatement();
stmt.execute(set_encoding);

PreparedStatement pstmt = con.prepareStatement(add_empl);

pstmt.setInt(1, employee.getClockNumber());
pstmt.setString(2, gson.toJson(employee.getPassport()));
pstmt.setString(3, gson.toJson(employee.getPosition()));
pstmt.setString(4, gson.toJson(employee.getEducation()));
pstmt.setString(5, gson.toJson(employee.getEmployment()));
pstmt.execute();
} catch (SQLException e) {
err.println("Seems like there is no access to database ^_^");
exit(70);
}
}

@Override
public void deleteEmployee(int clockNum) {
try (Connection con = DriverManager.getConnection(host, usr, pwd)) {

35
PreparedStatement pstmt = con.prepareStatement(del_empl);
pstmt.setInt(1, clockNum);
pstmt.execute();
} catch (SQLException e) {
err.println("Seems like there is no access to database ^_^");
exit(70);
}
}

@Override
public boolean isEmpty() {
boolean isEmpty = false;
try (Connection con = DriverManager.getConnection(host, usr, pwd)) {
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(select_all);
if (!rs.next()) {
isEmpty = true;
}
} catch (SQLException e) {
err.println("Seems like there is no access to database ^_^");
exit(70);
}

return isEmpty;
}
}

Main.java
package HR;

import HR.CLI.CLIManager;
import HR.CLI.CLine;
import HR.CLI.CommandHandler;
import HR.dataModel.EmployeeDAO;
import HR.dataModel.SQLDAO;

import java.io.File;
import java.util.Scanner;

import static java.lang.System.*;

public class Main {


public static void main(String[] args) {
EmployeeDAO employeeDAO = new SQLDAO(new File("wtf.config"));
CommandHandler commandHandler = new CommandHandler(new
CLIManager(employeeDAO));

Scanner scanner = new Scanner(System.in);


while (true) {

out.print("▶ ");
try {
CLine cLine = new CLine(scanner.nextLine());
commandHandler.handle(cLine);
} catch (IllegalArgumentException e) {
err.println(e.getMessage().replaceAll("\n", " "));
try {
Thread.sleep(100); // Kinda 'crutch', sometimes IDEA prints

36
// Next '->' to stdout faster then
exception...
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}

out.println();
}
}
}

37
Коды ошибок:

№ Коды ошибок Ошибка


1 2 Конфигурационный файл не существует или защищен от записи,
выведет "${configFileName} file doesn't exist or we can't read it"
2 9 В конфигурационном файле отсутствует необходимый параметр.
Выведет какие необходимые параметры отсутствуют
3 70 Критическая ошибка базы данных, выведет на экран код состояния SQL,
SQL код ошибки и сообщение об ошибке.

Код ошибки 2

38
Код ошибки 9

Код ошибки 70

39

Оценить