diff --git a/.gitignore b/.gitignore
index c5d12da..62617a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ out
target
*.iml
atlassian-ide-plugin.xml
+log
diff --git a/config/tomcat/setenv.bat b/config/tomcat/setenv.bat
new file mode 100644
index 0000000..ebbd659
--- /dev/null
+++ b/config/tomcat/setenv.bat
@@ -0,0 +1,4 @@
+rem run tomcat with JMX ability
+rem Run Tomcat as admin
+rem for remote connection add -Djava.rmi.server.hostname=TomcatServer_IP
+set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
diff --git a/pom.xml b/pom.xml
index c8a1c78..50ca237 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
ru.javawebinar
topjava
- jar
+ war
1.0-SNAPSHOT
@@ -13,13 +13,31 @@
1.8
+ 7.0.57
+
UTF-8
UTF-8
+
+ 4.1.6.RELEASE
+ 1.8.1.RELEASE
+
+
+ 1.1.2
+ 1.7.7
+
+
+ 4.12
+
+
+ 4.3.8.Final
+ 5.1.3.Final
+
+ 2.6.11
topjava
- install
+ package
org.apache.maven.plugins
@@ -34,11 +52,139 @@
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+ compile
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j.version}
+ runtime
+
+
+
+ org.slf4j
+ jul-to-slf4j
+ ${slf4j.version}
+ runtime
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+ runtime
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.0.1
+
+
+
+
+ org.springframework
+ spring-context-support
+ ${spring.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+
+ org.springframework.data
+ spring-data-jpa
+ ${spring-data-jpa.version}
+
+
+ org.hibernate
+ hibernate-entitymanager
+ ${hibernate.version}
+
+
+ org.hibernate
+ hibernate-validator
+ ${hibernate-validator.version}
+
+
+
+
+ net.sf.ehcache
+ ehcache-core
+ ${ehcache.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+ org.springframework
+ spring-test
+ ${spring.version}
+ test
+
+
+
+ hsqldb
+
+
+ org.hsqldb
+ hsqldb
+ 2.3.2
+
+
+
+
+ postgres
+
+
+ org.postgresql
+ postgresql
+ 9.4-1201-jdbc41
+
+
+ org.apache.tomcat
+ tomcat-jdbc
+ ${tomcat.version}
+
+
+
+ true
+
+
+
+
+ org.springframework
+ spring-framework-bom
+ ${spring.version}
+ pom
+ import
+
+
diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java
new file mode 100644
index 0000000..462aba7
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java
@@ -0,0 +1,16 @@
+package ru.javawebinar.topjava;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+public class LoggedUser {
+
+ public static int id() {
+ return 1;
+ }
+
+ public static int getCaloriesPerDay() {
+ return 2000;
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java
new file mode 100644
index 0000000..8ab6153
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java
@@ -0,0 +1,78 @@
+package ru.javawebinar.topjava;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+
+/**
+ * User: gkislin
+ * Date: 22.01.14
+ */
+public class LoggerWrapper {
+
+ private Logger logger;
+
+ public LoggerWrapper(Logger logger) {
+ this.logger = logger;
+ }
+
+ public static LoggerWrapper get(Class aClass) {
+ return new LoggerWrapper(LoggerFactory.getLogger(aClass));
+ }
+
+ public void debug(String msg) {
+ logger.debug(msg);
+ }
+
+ public void info(String msg, Object... arguments) {
+ logger.info(msg, arguments);
+ }
+
+ public void warn(String msg) {
+ logger.warn(msg);
+ }
+
+ public void warn(String msg, Throwable t) {
+ logger.warn(msg, t);
+ }
+
+ public void error(String msg) {
+ logger.error(msg);
+ }
+
+ public void error(String msg, Throwable t) {
+ logger.error(msg, t);
+ }
+
+ public boolean isDebug() {
+ return logger.isDebugEnabled();
+ }
+
+ public IllegalStateException getIllegalStateException(String msg) {
+ return getIllegalStateException(msg, null);
+ }
+
+ public IllegalStateException getIllegalStateException(String msg, Throwable e) {
+ logger.error(msg, e);
+ return new IllegalStateException(msg, e);
+ }
+
+ public IllegalArgumentException getIllegalArgumentException(String msg) {
+ return getIllegalArgumentException(msg, null);
+ }
+
+ public IllegalArgumentException getIllegalArgumentException(String msg, Throwable e) {
+ logger.error(msg, e);
+ return new IllegalArgumentException(msg, e);
+ }
+
+ public UnsupportedOperationException getUnsupportedOperationException(String msg) {
+ logger.error(msg);
+ return new UnsupportedOperationException(msg);
+ }
+
+ public NotFoundException getNotFoundException(String reason) {
+ logger.error(reason);
+ return new NotFoundException(reason);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/javawebinar/topjava/Main.java b/src/main/java/ru/javawebinar/topjava/Main.java
index 319e86c..8cc4da5 100644
--- a/src/main/java/ru/javawebinar/topjava/Main.java
+++ b/src/main/java/ru/javawebinar/topjava/Main.java
@@ -1,14 +1,30 @@
package ru.javawebinar.topjava;
+import java.util.function.Consumer;
+
/**
* User: gkislin
* Date: 15.01.2015
*
* @link http://javawebinar.ru/topjava/
- * @link http://caloriesmng.herokuapp.com/
*/
public class Main {
public static void main(String[] args) {
- System.out.format("Hello Topjava!");
+ execute(() -> {
+ System.out.println("Hello Topjava!");
+ });
+ consume(System.out::println, "Hello Topjava!");
+ }
+
+ private static void execute(Runnable runnable) {
+ System.out.println("Start runner");
+ runnable.run();
+ System.out.println("End runner");
+ }
+
+ private static void consume(Consumer consumer, String out) {
+ System.out.println("Start consume");
+ consumer.accept(out);
+ System.out.println("End consume");
}
}
diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java
new file mode 100644
index 0000000..caa126f
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java
@@ -0,0 +1,57 @@
+package ru.javawebinar.topjava.model;
+
+import ru.javawebinar.topjava.LoggerWrapper;
+
+import javax.persistence.*;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+@MappedSuperclass
+@Access(AccessType.FIELD)
+public class BaseEntity {
+ protected static final LoggerWrapper LOG = LoggerWrapper.get(BaseEntity.class);
+
+ public static final int START_SEQ = 100000;
+
+ @Id
+ @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1)
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
+ protected Integer id;
+
+ public BaseEntity() {
+ }
+
+ protected BaseEntity(Integer id) {
+ this.id = id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public boolean isNew() {
+ return (this.id == null);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BaseEntity that = (BaseEntity) o;
+ if (id == null || that.id == null) {
+ throw LOG.getIllegalStateException("Equals '" + this + "' and '" + that + "' with null id");
+ }
+ return id.equals(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return (id == null) ? 0 : id;
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java b/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java
new file mode 100644
index 0000000..e593d37
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java
@@ -0,0 +1,39 @@
+package ru.javawebinar.topjava.model;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.persistence.Column;
+import javax.persistence.MappedSuperclass;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+@MappedSuperclass
+public class NamedEntity extends BaseEntity {
+
+ @NotEmpty
+ @Column(name = "name", nullable = false)
+ protected String name;
+
+ public NamedEntity() {
+ }
+
+ protected NamedEntity(Integer id, String name) {
+ super(id);
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/model/Role.java b/src/main/java/ru/javawebinar/topjava/model/Role.java
new file mode 100644
index 0000000..f0de2b4
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/Role.java
@@ -0,0 +1,10 @@
+package ru.javawebinar.topjava.model;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+public enum Role {
+ ROLE_USER,
+ ROLE_ADMIN
+}
diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java
new file mode 100644
index 0000000..913cb8a
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/User.java
@@ -0,0 +1,116 @@
+package ru.javawebinar.topjava.model;
+
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+@Entity
+@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "unique_email")})
+@NamedQueries({
+ @NamedQuery(name = User.DELETE, query = "DELETE FROM User u WHERE u.id=:id"),
+ @NamedQuery(name = User.BY_EMAIL, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=?1"),
+ @NamedQuery(name = User.ALL_SORTED, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email"),
+})
+public class User extends NamedEntity {
+
+ public static final String DELETE = "User.delete";
+ public static final String ALL_SORTED = "User.getAllSorted";
+ public static final String BY_EMAIL = "User.getByEmail";
+
+ @Column(name = "email", nullable = false, unique = true)
+ @Email
+ @NotEmpty
+ protected String email;
+
+ @Column(name = "password", nullable = false)
+ @NotEmpty
+ @Length(min = 5)
+ protected String password;
+
+ @Column(name = "enabled", nullable = false)
+ protected boolean enabled = true;
+
+ @Column(name = "registered", columnDefinition = "timestamp default now()")
+ protected Date registered = new Date();
+
+ @Enumerated(EnumType.STRING)
+ @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
+ @Column(name = "role")
+ @ElementCollection(fetch = FetchType.EAGER)
+ protected Set roles;
+
+ public User() {
+ }
+
+ public User(Integer id, String name, String email, String password, Role role, Role... roles) {
+ this(id, name, email, password, true, EnumSet.of(role, roles));
+ }
+
+ public User(User u) {
+ this(u.getId(), u.getName(), u.getEmail(), u.getPassword(), u.isEnabled(), u.getRoles());
+ }
+
+ public User(Integer id, String name, String email, String password, boolean enabled, Set roles) {
+ super(id, name);
+ this.email = email;
+ this.password = password;
+ this.enabled = enabled;
+ this.roles = roles;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Date getRegistered() {
+ return registered;
+ }
+
+ public void setRegistered(Date registered) {
+ this.registered = registered;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public Set getRoles() {
+ return roles;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public String toString() {
+ return "User (" +
+ "id=" + id +
+ ", email=" + email +
+ ", name=" + name +
+ ", enabled=" + enabled +
+ ", roles=" + roles +
+ ')';
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java
new file mode 100644
index 0000000..27f2c51
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java
@@ -0,0 +1,87 @@
+package ru.javawebinar.topjava.model;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * GKislin
+ * 11.01.2015.
+ */
+@NamedQueries({
+ @NamedQuery(name = UserMeal.GET, query = "SELECT m FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId"),
+ @NamedQuery(name = UserMeal.ALL_SORTED, query = "SELECT m FROM UserMeal m WHERE m.user.id=:userId ORDER BY m.dateTime DESC"),
+ @NamedQuery(name = UserMeal.DELETE_ALL, query = "DELETE FROM UserMeal i WHERE i.user.id=:userId"),
+ @NamedQuery(name = UserMeal.DELETE, query = "DELETE FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId"),
+ @NamedQuery(name = UserMeal.GET_BETWEEN,
+ query = "SELECT m from UserMeal m WHERE m.user.id=:userId "+
+ " AND m.dateTime BETWEEN :startDate AND :endDate ORDER BY m.dateTime DESC"),
+
+// @NamedQuery(name = UserMeal.UPDATE, query = "UPDATE UserMeal m SET m.dateTime = :datetime, m.calories= :calories," +
+// "m.description=:desc where m.id=:id and m.user.id=:userId")
+})
+
+@Entity
+@Table(name = "meals")
+public class UserMeal extends BaseEntity{
+ public static final String GET = "UserMeal.get";
+ public static final String ALL_SORTED = "UserMeal.getAll";
+ public static final String DELETE = "UserMeal.delete";
+ public static final String DELETE_ALL = "UserMeal.deleteAll";
+ public static final String GET_BETWEEN = "UserMeal.getBetween";
+// public static final String UPDATE = "UserMeal.update";
+
+ @Column(name = "time", nullable = false)
+ @NotNull
+ protected LocalDateTime dateTime;
+
+ @Column(name = "description", nullable = false)
+ @NotEmpty
+ protected String description;
+
+ @Column(name = "calories")
+ protected int calories;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id", nullable = false)
+ @NotNull
+// http://stackoverflow.com/questions/9887242/using-postgresql-why-doesnt-hibernate-jpa-create-cascade-constraints/9925761#9925761
+ private User user;
+
+ public UserMeal() {
+ }
+
+ public UserMeal(Integer id, LocalDateTime dateTime, String description, int calories) {
+ super(id);
+ this.dateTime = dateTime;
+ this.description = description;
+ this.calories = calories;
+ }
+
+ public LocalDateTime getDateTime() {
+ return dateTime;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public int getCalories() {
+ return calories;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ @Override
+ public String toString() {
+ return "Meal(" + id + ", " + dateTime + ", '" + description + "', calories:" + calories + ')';
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/model/converter/LocalDateTimeConverter.java b/src/main/java/ru/javawebinar/topjava/model/converter/LocalDateTimeConverter.java
new file mode 100644
index 0000000..eaf8917
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/converter/LocalDateTimeConverter.java
@@ -0,0 +1,24 @@
+package ru.javawebinar.topjava.model.converter;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+
+/**
+ * GKislin
+ * 08.01.2015.
+ * @link https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa
+ */
+@Converter(autoApply = true)
+public class LocalDateTimeConverter implements AttributeConverter {
+ @Override
+ public Timestamp convertToDatabaseColumn(LocalDateTime ldt) {
+ return Timestamp.valueOf(ldt);
+ }
+
+ @Override
+ public LocalDateTime convertToEntityAttribute(Timestamp ts) {
+ return ts.toLocalDateTime();
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java
new file mode 100644
index 0000000..89e7303
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java
@@ -0,0 +1,33 @@
+package ru.javawebinar.topjava.repository;
+
+import ru.javawebinar.topjava.model.UserMeal;
+
+import ru.javawebinar.topjava.model.UserMeal;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+public interface UserMealRepository {
+ // null if updated meal do not belong to userId
+ UserMeal save(UserMeal userMeal, int userId);
+
+ // false if meal do not belong to userId
+ boolean delete(int id, int userId);
+
+ // null if meal do not belong to userId
+ UserMeal get(int id, int userId);
+
+ // ORDERED DATE, TIME
+ List getAll(int userId);
+
+ void deleteAll(int userId);
+
+ List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId);
+
+
+
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java
new file mode 100644
index 0000000..24c1c45
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java
@@ -0,0 +1,24 @@
+package ru.javawebinar.topjava.repository;
+
+import ru.javawebinar.topjava.model.User;
+
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+public interface UserRepository {
+ User save(User user);
+
+ // false if not found
+ boolean delete(int id);
+
+ // null if not found
+ User get(int id);
+
+ // null if not found
+ User getByEmail(String email);
+
+ List getAll();
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java
new file mode 100644
index 0000000..aef2d31
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java
@@ -0,0 +1,45 @@
+package ru.javawebinar.topjava.repository.datajpa;
+
+import org.springframework.stereotype.Repository;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.repository.UserMealRepository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * GKislin
+ * 27.03.2015.
+ */
+@Repository
+public class DataJpaUserMealRepositoryImpl implements UserMealRepository{
+ @Override
+ public UserMeal save(UserMeal userMeal, int userId) {
+ return null;
+ }
+
+ @Override
+ public boolean delete(int id, int userId) {
+ return false;
+ }
+
+ @Override
+ public UserMeal get(int id, int userId) {
+ return null;
+ }
+
+ @Override
+ public List getAll(int userId) {
+ return null;
+ }
+
+ @Override
+ public void deleteAll(int userId) {
+
+ }
+
+ @Override
+ public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) {
+ return null;
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java
new file mode 100644
index 0000000..139946a
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java
@@ -0,0 +1,47 @@
+package ru.javawebinar.topjava.repository.datajpa;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Repository;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.repository.UserRepository;
+
+import java.util.List;
+
+/**
+ * GKislin
+ * 27.03.2015.
+ */
+
+@Repository
+public class DataJpaUserRepositoryImpl implements UserRepository {
+ private static final Sort SORT_NAME_EMAIL = new Sort("name", "email");
+
+ @Autowired
+ private ProxyUserRepository proxy;
+
+ @Override
+ public User save(User user) {
+ return proxy.save(user);
+ }
+
+ @Override
+ public boolean delete(int id) {
+ return proxy.delete(id) != 0;
+ }
+
+ @Override
+ public User get(int id) {
+ return proxy.findOne(id);
+ }
+
+ @Override
+ public User getByEmail(String email) {
+ return proxy.getByEmail(email);
+ }
+
+ @Override
+ public List getAll() {
+ return proxy.findAll(SORT_NAME_EMAIL);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java
new file mode 100644
index 0000000..092d847
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java
@@ -0,0 +1,37 @@
+package ru.javawebinar.topjava.repository.datajpa;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.transaction.annotation.Transactional;
+import ru.javawebinar.topjava.model.User;
+
+import java.util.List;
+
+/**
+ * GKislin
+ * 27.03.2015.
+ */
+@Transactional(readOnly = true)
+public interface ProxyUserRepository extends JpaRepository {
+
+ @Transactional
+ @Modifying
+// @Query(name = User.DELETE)
+ @Query("DELETE FROM User u WHERE u.id=:id")
+ int delete(@Param("id") int id);
+
+ @Override
+ @Transactional
+ User save(User user);
+
+ @Override
+ User findOne(Integer id);
+
+ @Override
+ List findAll(Sort sort);
+
+ User getByEmail(String email);
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java
new file mode 100644
index 0000000..739cea4
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java
@@ -0,0 +1,97 @@
+package ru.javawebinar.topjava.repository.jdbc;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.support.DataAccessUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
+import org.springframework.stereotype.Repository;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.repository.UserMealRepository;
+
+import javax.sql.DataSource;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 26.08.2014
+ */
+
+@Repository
+public class JdbcUserMealRepositoryImpl implements UserMealRepository {
+
+ private static final RowMapper ROW_MAPPER =
+ (rs, rowNum) ->
+ new UserMeal(rs.getInt("id"), rs.getTimestamp("dateTime").toLocalDateTime(), rs.getString("description"), rs.getInt("calories"));
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Autowired
+ private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
+
+ private SimpleJdbcInsert insertUserMeal;
+
+ @Autowired
+ public JdbcUserMealRepositoryImpl(DataSource dataSource) {
+ this.insertUserMeal = new SimpleJdbcInsert(dataSource)
+ .withTableName("meals")
+ .usingGeneratedKeyColumns("id");
+ }
+
+ @Override
+ public UserMeal save(UserMeal userMeal, int userId) {
+ MapSqlParameterSource map = new MapSqlParameterSource()
+ .addValue("id", userMeal.getId())
+ .addValue("description", userMeal.getDescription())
+ .addValue("calories", userMeal.getCalories())
+ .addValue("datetime", Timestamp.valueOf(userMeal.getDateTime()))
+ .addValue("user_id", userId);
+
+ if (userMeal.isNew()) {
+ Number newId = insertUserMeal.executeAndReturnKey(map);
+ userMeal.setId(newId.intValue());
+ } else {
+ if (namedParameterJdbcTemplate.update(
+ "UPDATE meals SET description=:description, calories=:calories, datetime=:datetime " +
+ " WHERE id=:id AND user_id=:user_id", map) == 0) {
+ return null;
+ }
+ }
+ return userMeal;
+ }
+
+ @Override
+ public boolean delete(int id, int userId) {
+ return jdbcTemplate.update("DELETE FROM meals WHERE id=? AND user_id=?", id, userId) != 0;
+ }
+
+ @Override
+ public void deleteAll(int userId) {
+ jdbcTemplate.update("DELETE FROM meals WHERE user_id=?", userId);
+ }
+
+ @Override
+ public UserMeal get(int id, int userId) {
+ List userMeals = jdbcTemplate.query(
+ "SELECT * FROM meals WHERE id = ? AND user_id = ?", ROW_MAPPER, id, userId);
+ return DataAccessUtils.singleResult(userMeals);
+ }
+
+ @Override
+ public List getAll(int userId) {
+ return jdbcTemplate.query(
+ "SELECT * FROM meals WHERE user_id=? ORDER BY dateTime DESC", ROW_MAPPER, userId);
+ }
+
+ @Override
+ public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) {
+ return jdbcTemplate.query(
+ "SELECT * FROM meals WHERE user_id=? AND dateTime BETWEEN ? AND ? ORDER BY dateTime DESC",
+ ROW_MAPPER, userId, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java
new file mode 100644
index 0000000..35120f2
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java
@@ -0,0 +1,87 @@
+package ru.javawebinar.topjava.repository.jdbc;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
+import org.springframework.stereotype.Repository;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.repository.UserRepository;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 26.08.2014
+ */
+
+@Repository
+public class JdbcUserRepositoryImpl implements UserRepository {
+
+ private static final BeanPropertyRowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(User.class);
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Autowired
+ private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
+
+ private SimpleJdbcInsert insertUser;
+
+ @Autowired
+ public JdbcUserRepositoryImpl(DataSource dataSource) {
+ this.insertUser = new SimpleJdbcInsert(dataSource)
+ .withTableName("USERS")
+ .usingGeneratedKeyColumns("id");
+ }
+
+ @Override
+ public User save(User user) {
+ MapSqlParameterSource map = new MapSqlParameterSource()
+ .addValue("id", user.getId())
+ .addValue("name", user.getName())
+ .addValue("email", user.getEmail())
+ .addValue("password", user.getPassword())
+ .addValue("registered", user.getRegistered())
+ .addValue("enabled", user.isEnabled());
+
+ if (user.isNew()) {
+ Number newKey = insertUser.executeAndReturnKey(map);
+ user.setId(newKey.intValue());
+ } else {
+ namedParameterJdbcTemplate.update(
+ "UPDATE users SET name=:name, email=:email, password=:password, " +
+ "registered=:registered, enabled=:enabled WHERE id=:id", map);
+ }
+ return user;
+ }
+
+ @Override
+ public boolean delete(int id) {
+ return jdbcTemplate.update("DELETE FROM users WHERE id=?", id) != 0;
+ }
+
+ @Override
+ public User get(int id) {
+ return jdbcTemplate.queryForObject(
+ "SELECT id, name, email, password, registered, enabled FROM users WHERE id=?",
+ ROW_MAPPER, id);
+ }
+
+ @Override
+ public User getByEmail(String email) {
+ return jdbcTemplate.queryForObject(
+ "SELECT id, name, email, password, registered, enabled FROM users WHERE email=?",
+ ROW_MAPPER, email);
+ }
+
+ @Override
+ public List getAll() {
+ return jdbcTemplate.query(
+ "SELECT id, name, email, password, registered, enabled FROM users ORDER BY name, email",
+ ROW_MAPPER);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java
new file mode 100644
index 0000000..fe180a7
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java
@@ -0,0 +1,90 @@
+package ru.javawebinar.topjava.repository.jpa;
+
+import org.springframework.dao.support.DataAccessUtils;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.repository.UserMealRepository;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 26.08.2014
+ */
+
+@Repository
+@Transactional(readOnly = true)
+public class JpaUserMealRepositoryImpl implements UserMealRepository {
+
+ @PersistenceContext
+ private EntityManager em;
+
+ @Override
+ @Transactional
+ public UserMeal save(UserMeal userMeal, int userId) {
+ User ref = em.getReference(User.class, userId);
+ userMeal.setUser(ref);
+
+ if (userMeal.isNew()) {
+ em.persist(userMeal);
+ } else {
+ if (get(userMeal.getId(), userId) == null) return null;
+ em.merge(userMeal);
+/*
+ if (em.createNamedQuery(UserMeal.UPDATE)
+ .setParameter("datetime", userMeal.getDateTime())
+ .setParameter("calories", userMeal.getCalories())
+ .setParameter("desc", userMeal.getDescription())
+ .setParameter("id", userMeal.getId())
+ .setParameter("userId", userId).executeUpdate() == 0) {
+ return null;
+ }
+*/
+ }
+ return userMeal;
+ }
+
+ @Override
+ @Transactional
+ public boolean delete(int id, int userId) {
+ return em.createNamedQuery(UserMeal.DELETE)
+ .setParameter("id", id)
+ .setParameter("userId", userId)
+ .executeUpdate() != 0;
+ }
+
+ @Override
+ public UserMeal get(int id, int userId) {
+ List userMeals = em.createNamedQuery(UserMeal.GET, UserMeal.class)
+ .setParameter("id", id)
+ .setParameter("userId", userId)
+ .getResultList();
+ return DataAccessUtils.singleResult(userMeals);
+ }
+
+ @Override
+ public List getAll(int userId) {
+ return em.createNamedQuery(UserMeal.ALL_SORTED, UserMeal.class)
+ .setParameter("userId", userId)
+ .getResultList();
+ }
+
+ @Override
+ @Transactional
+ public void deleteAll(int userId) {
+ em.createNamedQuery(UserMeal.DELETE_ALL).setParameter("userId", userId).executeUpdate();
+ }
+
+ @Override
+ public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) {
+ return em.createNamedQuery(UserMeal.GET_BETWEEN, UserMeal.class)
+ .setParameter("userId", userId)
+ .setParameter("startDate", startDate)
+ .setParameter("endDate", endDate).getResultList();
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java
new file mode 100644
index 0000000..6ffc1c8
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java
@@ -0,0 +1,71 @@
+package ru.javawebinar.topjava.repository.jpa;
+
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.repository.UserRepository;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 29.08.2014
+ */
+@Repository
+@Transactional(readOnly = true)
+public class JpaUserRepositoryImpl implements UserRepository {
+
+/*
+ @Autowired
+ private SessionFactory sessionFactory;
+
+ private Session openSession() {
+ return sessionFactory.getCurrentSession();
+ }
+*/
+
+ @PersistenceContext
+ private EntityManager em;
+
+ @Override
+ @Transactional
+ public User save(User user) {
+ if (user.isNew()) {
+ em.persist(user);
+ } else {
+ em.merge(user);
+ }
+ return user;
+ }
+
+ @Override
+ public User get(int id) {
+ return em.find(User.class, id);
+ }
+
+ @Override
+ @Transactional
+ public boolean delete(int id) {
+
+/*
+ User ref = em.getReference(User.class, id);
+ em.remove(ref);
+
+ TypedQuery query = em.createQuery("DELETE FROM User u WHERE u.id=:id", User.class);
+ return query.setParameter("id", id).executeUpdate() != 0;
+*/
+ return em.createNamedQuery(User.DELETE).setParameter("id", id).executeUpdate() != 0;
+ }
+
+ @Override
+ public User getByEmail(String email) {
+ return em.createNamedQuery(User.BY_EMAIL, User.class).setParameter(1, email).getSingleResult();
+ }
+
+ @Override
+ public List getAll() {
+ return em.createNamedQuery(User.ALL_SORTED, User.class).getResultList();
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java
new file mode 100644
index 0000000..9507e1c
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java
@@ -0,0 +1,32 @@
+package ru.javawebinar.topjava.service;
+
+import ru.javawebinar.topjava.model.UserMeal;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.List;
+
+/**
+ * GKislin
+ * 15.06.2015.
+ */
+public interface UserMealService {
+ UserMeal get(int id, int userId);
+
+ void delete(int id, int userId);
+
+ default List getBetweenDates(LocalDate startDate, LocalDate endDate, int userId) {
+ return getBetweenDateTimes(LocalDateTime.of(startDate, LocalTime.MIN), LocalDateTime.of(endDate, LocalTime.MAX), userId);
+ }
+
+ List getBetweenDateTimes(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId);
+
+ List getAll(int userId);
+
+ void deleteAll(int userId);
+
+ UserMeal update(UserMeal meal, int userId);
+
+ UserMeal save(UserMeal meal, int userId);
+}
diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java
new file mode 100644
index 0000000..f8e2384
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java
@@ -0,0 +1,56 @@
+package ru.javawebinar.topjava.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.repository.UserMealRepository;
+import ru.javawebinar.topjava.util.exception.ExceptionUtil;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+@Service
+public class UserMealServiceImpl implements UserMealService {
+
+ @Autowired
+ private UserMealRepository repository;
+
+ @Override
+ public UserMeal get(int id, int userId) {
+ return ExceptionUtil.check(repository.get(id, userId), id);
+ }
+
+ @Override
+ public void delete(int id, int userId) {
+ ExceptionUtil.check(repository.delete(id, userId), id);
+ }
+
+ @Override
+ public List getBetweenDateTimes(LocalDateTime startDate, LocalDateTime endDate, int userId) {
+ return repository.getBetween(startDate, endDate, userId);
+ }
+
+ @Override
+ public List getAll(int userId) {
+ return repository.getAll(userId);
+ }
+
+ @Override
+ public void deleteAll(int userId) {
+ repository.deleteAll(userId);
+ }
+
+ @Override
+ public UserMeal update(UserMeal meal, int userId) {
+ return ExceptionUtil.check(repository.save(meal, userId), meal.getId());
+ }
+
+ @Override
+ public UserMeal save(UserMeal meal, int userId) {
+ return repository.save(meal, userId);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java
new file mode 100644
index 0000000..52cbec5
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java
@@ -0,0 +1,28 @@
+package ru.javawebinar.topjava.service;
+
+
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+public interface UserService {
+
+ User save(User user);
+
+ void delete(int id) throws NotFoundException;
+
+ User get(int id) throws NotFoundException;
+
+ User getByEmail(String email) throws NotFoundException;
+
+ List getAll();
+
+ void update(User user) throws NotFoundException;
+
+ public void evictCache();
+}
diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java
new file mode 100644
index 0000000..15e24ae
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java
@@ -0,0 +1,56 @@
+package ru.javawebinar.topjava.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.repository.UserRepository;
+import ru.javawebinar.topjava.util.exception.ExceptionUtil;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+
+import java.util.List;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+@Service
+public class UserServiceImpl implements UserService {
+
+ @Autowired
+ private UserRepository repository;
+
+ @CacheEvict(value = "users", allEntries = true)
+ public User save(User user) {
+ return repository.save(user);
+ }
+
+ @CacheEvict(value = "users", allEntries = true)
+ public void delete(int id) {
+ ExceptionUtil.check(repository.delete(id), id);
+ }
+
+ public User get(int id) throws NotFoundException {
+ return ExceptionUtil.check(repository.get(id), id);
+ }
+
+ public User getByEmail(String email) throws NotFoundException {
+ return ExceptionUtil.check(repository.getByEmail(email), "email=" + email);
+ }
+
+ @Cacheable("users")
+ public List getAll() {
+ return repository.getAll();
+ }
+
+ @CacheEvict(value = "users", allEntries = true)
+ public void update(User user) throws NotFoundException {
+ ExceptionUtil.check(repository.save(user), user.getId());
+ }
+
+ @CacheEvict(value = "users", allEntries = true)
+ @Override
+ public void evictCache() {
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/to/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/to/UserMealWithExceed.java
new file mode 100644
index 0000000..f2773a1
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/to/UserMealWithExceed.java
@@ -0,0 +1,37 @@
+package ru.javawebinar.topjava.to;
+
+import java.time.LocalDateTime;
+
+/**
+ * GKislin
+ * 11.01.2015.
+ */
+public class UserMealWithExceed {
+ protected final Integer id;
+
+ protected final LocalDateTime dateTime;
+
+ protected final String description;
+
+ protected final int calories;
+
+ protected final boolean exceed;
+
+ public UserMealWithExceed(Integer id, LocalDateTime dateTime, String description, int calories, boolean exceed) {
+ this.id = id;
+ this.dateTime = dateTime;
+ this.description = description;
+ this.calories = calories;
+ this.exceed = exceed;
+ }
+
+ @Override
+ public String toString() {
+ return "UserMealWithExceed{" +
+ "dateTime=" + dateTime +
+ ", description='" + description + '\'' +
+ ", calories=" + calories +
+ ", exceed=" + exceed +
+ '}';
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java
new file mode 100644
index 0000000..02399b7
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java
@@ -0,0 +1,13 @@
+package ru.javawebinar.topjava.util;
+
+import java.time.LocalTime;
+
+/**
+ * GKislin
+ * 07.01.2015.
+ */
+public class TimeUtil {
+ public static boolean isBetween(LocalTime lt, LocalTime startTime, LocalTime endTime) {
+ return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) <= 0;
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java
new file mode 100644
index 0000000..969515b
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java
@@ -0,0 +1,28 @@
+package ru.javawebinar.topjava.util;
+
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.to.UserMealWithExceed;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * GKislin
+ * 31.05.2015.
+ */
+public class UserMealsUtil {
+
+ public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) {
+ Map caloriesSumByDate = mealList.stream().collect(Collectors.groupingBy(um -> um.getDateTime().toLocalDate(),
+ Collectors.summingInt(UserMeal::getCalories)));
+
+ return mealList.stream()
+ .filter(um->TimeUtil.isBetween(um.getDateTime().toLocalTime(), startTime, endTime))
+ .map(um->new UserMealWithExceed(um.getId(), um.getDateTime(), um.getDescription(), um.getCalories(),
+ caloriesSumByDate.get(um.getDateTime().toLocalDate())> caloriesPerDay))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java
new file mode 100644
index 0000000..295aada
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java
@@ -0,0 +1,29 @@
+package ru.javawebinar.topjava.util.exception;
+
+
+import ru.javawebinar.topjava.LoggerWrapper;
+
+/**
+ * User: gkislin
+ * Date: 14.05.2014
+ */
+public class ExceptionUtil {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(ExceptionUtil.class);
+
+ public static void check(boolean found, int id) {
+ check(found, "id=" + id);
+ }
+
+ public static T check(T object, int id) {
+ return check(object, "id=" + id);
+ }
+
+ public static T check(T object, String msg) {
+ check(object != null, msg);
+ return object;
+ }
+
+ public static void check(boolean found, String msg) {
+ if (!found) throw LOG.getNotFoundException("Not found entity with " + msg);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java b/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java
new file mode 100644
index 0000000..7a770f0
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java
@@ -0,0 +1,11 @@
+package ru.javawebinar.topjava.util.exception;
+
+/**
+ * User: gkislin
+ * Date: 19.08.2014
+ */
+public class NotFoundException extends RuntimeException {
+ public NotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java
new file mode 100644
index 0000000..1b72b09
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java
@@ -0,0 +1,22 @@
+package ru.javawebinar.topjava.web;
+
+import ru.javawebinar.topjava.LoggerWrapper;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * User: gkislin
+ * Date: 19.08.2014
+ */
+public class MealServlet extends HttpServlet {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(MealServlet.class);
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ LOG.debug("redirect to mealList");
+ response.sendRedirect("mealList.jsp");
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java
new file mode 100644
index 0000000..eb2188b
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java
@@ -0,0 +1,24 @@
+package ru.javawebinar.topjava.web;
+
+import ru.javawebinar.topjava.LoggerWrapper;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * User: gkislin
+ * Date: 19.08.2014
+ */
+public class UserServlet extends HttpServlet {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(UserServlet.class);
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ LOG.debug("redirect to userList");
+
+// request.getRequestDispatcher("/userList.jsp").forward(request, response);
+ response.sendRedirect("userList.jsp");
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java
new file mode 100644
index 0000000..3a0e126
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java
@@ -0,0 +1,72 @@
+package ru.javawebinar.topjava.web.meal;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import ru.javawebinar.topjava.LoggedUser;
+import ru.javawebinar.topjava.LoggerWrapper;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.service.UserMealService;
+import ru.javawebinar.topjava.to.UserMealWithExceed;
+import ru.javawebinar.topjava.util.UserMealsUtil;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+@Controller
+public class UserMealRestController {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(UserMealRestController.class);
+
+ @Autowired
+ private UserMealService service;
+
+ public UserMeal get(int id) {
+ int userId = LoggedUser.id();
+ LOG.info("get meal {} for User {}", id, userId);
+ return service.get(id, userId);
+ }
+
+ public void delete(int id) {
+ int userId = LoggedUser.id();
+ LOG.info("delete meal {} for User {}", id, userId);
+ service.delete(id, userId);
+ }
+
+ public List getAll() {
+ int userId = LoggedUser.id();
+ LOG.info("getAll for User {}", userId);
+ return UserMealsUtil.getFilteredMealsWithExceeded(
+ service.getAll(userId), LocalTime.MIN, LocalTime.MAX, LoggedUser.getCaloriesPerDay()
+ );
+ }
+
+ public void deleteAll() {
+ int userId = LoggedUser.id();
+ LOG.info("deleteAll for User {}", userId);
+ service.deleteAll(userId);
+ }
+
+ public void update(UserMeal meal) {
+ int userId = LoggedUser.id();
+ LOG.info("update {} for User {}", meal, userId);
+ service.update(meal, userId);
+ }
+
+ public UserMeal create(UserMeal meal) {
+ int userId = LoggedUser.id();
+ LOG.info("create {} for User {}", meal, userId);
+ return service.save(meal, userId);
+ }
+
+ public List getBetween(LocalDate startDate, LocalTime startTime, LocalDate endDate, LocalTime endTime) {
+ int userId = LoggedUser.id();
+ LOG.info("getBetween dates {} - {} for time {} - {} for User {}", startDate, endDate, startTime, endTime, userId);
+ return UserMealsUtil.getFilteredMealsWithExceeded(
+ service.getBetweenDates(startDate, endDate, userId), startTime, endTime, LoggedUser.getCaloriesPerDay()
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminUserRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminUserRestController.java
new file mode 100644
index 0000000..7ba6585
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminUserRestController.java
@@ -0,0 +1,51 @@
+package ru.javawebinar.topjava.web.user;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import ru.javawebinar.topjava.LoggerWrapper;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.service.UserService;
+
+import java.util.List;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+@Controller
+public class AdminUserRestController {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(UserRestController.class);
+
+ @Autowired
+ private UserService service;
+
+ public List getAll() {
+ LOG.info("getAll");
+ return service.getAll();
+ }
+
+ public User get(int id) {
+ LOG.info("get " + id);
+ return service.get(id);
+ }
+
+ public User create(User user) {
+ LOG.info("create " + user);
+ return service.save(user);
+ }
+
+ public void delete(int id) {
+ LOG.info("delete " + id);
+ service.delete(id);
+ }
+
+ public void update(User user) {
+ LOG.info("update " + user);
+ service.update(user);
+ }
+
+ public User getByMail(String email) {
+ LOG.info("getByEmail " + email);
+ return service.getByEmail(email);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/web/user/UserRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/UserRestController.java
new file mode 100644
index 0000000..ff19da4
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/user/UserRestController.java
@@ -0,0 +1,38 @@
+package ru.javawebinar.topjava.web.user;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import ru.javawebinar.topjava.LoggedUser;
+import ru.javawebinar.topjava.LoggerWrapper;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.service.UserService;
+
+/**
+ * GKislin
+ * 06.03.2015.
+ */
+@Controller
+public class UserRestController {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(UserRestController.class);
+
+ @Autowired
+ private UserService service;
+
+ public User get() {
+ int id = LoggedUser.id();
+ LOG.info("get", id);
+ return service.get(id);
+ }
+
+ public void delete() {
+ int id = LoggedUser.id();
+ LOG.info("delete {}", id);
+ service.delete(id);
+ }
+
+ public void update(User user) {
+ int id = LoggedUser.id();
+ LOG.info("update");
+ service.update(user);
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/cache/ehcache.xml b/src/main/resources/cache/ehcache.xml
new file mode 100644
index 0000000..8d42001
--- /dev/null
+++ b/src/main/resources/cache/ehcache.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/cache/ehcache.xsd b/src/main/resources/cache/ehcache.xsd
new file mode 100644
index 0000000..bfc19dd
--- /dev/null
+++ b/src/main/resources/cache/ehcache.xsd
@@ -0,0 +1,419 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties
new file mode 100644
index 0000000..972e02e
--- /dev/null
+++ b/src/main/resources/db/hsqldb.properties
@@ -0,0 +1,12 @@
+#database.url=jdbc:hsqldb:file:D:/temp/topjava
+database.url=jdbc:hsqldb:mem:topjava
+
+database.username=sa
+database.password=
+database.driverClassName=org.hsqldb.jdbcDriver
+
+database.init=true
+jdbc.initLocation=initDB_hsql.sql
+jpa.showSql=true
+hibernate.format_sql=true
+hibernate.use_sql_comments=true
diff --git a/src/main/resources/db/initDB_hsql.sql b/src/main/resources/db/initDB_hsql.sql
new file mode 100644
index 0000000..f6856a8
--- /dev/null
+++ b/src/main/resources/db/initDB_hsql.sql
@@ -0,0 +1,35 @@
+DROP TABLE user_roles IF EXISTS;
+DROP TABLE meals IF EXISTS;
+DROP TABLE users IF EXISTS;
+DROP SEQUENCE global_seq IF EXISTS;
+
+CREATE SEQUENCE GLOBAL_SEQ AS INTEGER START WITH 100000;
+
+CREATE TABLE users
+(
+ id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
+ name VARCHAR(255),
+ email VARCHAR(255) NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ registered TIMESTAMP DEFAULT now(),
+ enabled BOOLEAN DEFAULT TRUE
+);
+CREATE UNIQUE INDEX user_email_key ON USERS ( email );
+
+CREATE TABLE user_roles
+(
+ user_id INTEGER NOT NULL,
+ role VARCHAR(255),
+ CONSTRAINT user_roles_idx UNIQUE (user_id, role),
+ FOREIGN KEY ( user_id ) REFERENCES USERS ( id ) ON DELETE CASCADE
+);
+
+CREATE TABLE meals
+(
+ id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
+ datetime TIMESTAMP NOT NULL,
+ description VARCHAR(255) NOT NULL,
+ calories INT,
+ user_id INTEGER NOT NULL,
+ FOREIGN KEY ( user_id ) REFERENCES USERS ( id ) ON DELETE CASCADE
+);
diff --git a/src/main/resources/db/initDB_postgres.sql b/src/main/resources/db/initDB_postgres.sql
new file mode 100644
index 0000000..36a2207
--- /dev/null
+++ b/src/main/resources/db/initDB_postgres.sql
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS user_roles;
+DROP TABLE IF EXISTS meals;
+DROP TABLE IF EXISTS users;
+DROP SEQUENCE IF EXISTS global_seq;
+
+CREATE SEQUENCE global_seq START 100000;
+
+CREATE TABLE users
+(
+ id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
+ name VARCHAR,
+ email VARCHAR NOT NULL,
+ password VARCHAR NOT NULL,
+ registered TIMESTAMP DEFAULT now(),
+ enabled BOOL DEFAULT TRUE
+);
+CREATE UNIQUE INDEX unique_email ON USERS (email);
+
+CREATE TABLE user_roles
+(
+ user_id INTEGER NOT NULL,
+ role VARCHAR,
+ CONSTRAINT user_roles_idx UNIQUE (user_id, role),
+ FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
+);
+
+CREATE TABLE meals (
+ id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
+ user_id INTEGER NOT NULL,
+ datetime TIMESTAMP NOT NULL,
+ description TEXT NOT NULL,
+ calories INT,
+ FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
+);
diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql
new file mode 100644
index 0000000..af9099a
--- /dev/null
+++ b/src/main/resources/db/populateDB.sql
@@ -0,0 +1,22 @@
+DELETE FROM user_roles;
+DELETE FROM meals;
+DELETE FROM users;
+ALTER SEQUENCE global_seq RESTART WITH 100000;
+
+-- password
+INSERT INTO users (name, email, password)
+VALUES ('User', 'user@yandex.ru', 'password');
+-- admin
+INSERT INTO users (name, email, password)
+VALUES ('Admin', 'admin@gmail.com', 'admin');
+
+INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 100000);
+INSERT INTO user_roles (role, user_id) VALUES ('ROLE_ADMIN', 100001);
+
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-05-30 10:00:00', 'Завтрак', 500, 100000);
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-05-30 13:00:00', 'Обед', 1000, 100000);
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-05-30 20:00:00', 'Ужин', 500, 100000);
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-05-31 10:00:00', 'Завтрак', 500, 100000);
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-05-31 13:00:00', 'Обед', 1000, 100000);
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-05-31 20:00:00', 'Ужин', 510, 100000);
+INSERT INTO meals (datetime, description, calories, user_id) VALUES ('2015-06-01 14:00:00', 'Админ-Ланч', 2001, 100001);
diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties
new file mode 100644
index 0000000..269bc2a
--- /dev/null
+++ b/src/main/resources/db/postgres.properties
@@ -0,0 +1,11 @@
+#database.url=jdbc:postgresql://ec2-54-217-202-110.eu-west-1.compute.amazonaws.com:5432/dehm6lvm8bink0?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
+#database.username=wegxlfzjjgxaxy
+#database.password=SSQyKKE_e93kiUCR-ehzMcKCxZ
+
+database.init=true
+jdbc.initLocation=initDB_postgres.sql
+database.driverClassName=org.postgresql.Driver
+
+database.url=jdbc:postgresql://localhost:5432/topjava
+database.username=test_user
+database.password=test_user
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
new file mode 100644
index 0000000..4ee2916
--- /dev/null
+++ b/src/main/resources/logback.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ true
+
+
+
+
+
+
+ ${TOPJAVA_ROOT}/log/topjava.log
+
+
+ UTF-8
+ %date %-5level %logger{0} [%file:%line] %msg%n
+
+
+
+
+
+ UTF-8
+ %-5level %logger{0} [%file:%line] %msg%n
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml
new file mode 100644
index 0000000..995ebf9
--- /dev/null
+++ b/src/main/resources/spring/spring-app.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml
new file mode 100644
index 0000000..44cd573
--- /dev/null
+++ b/src/main/resources/spring/spring-db.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/spring/spring-tools.xml b/src/main/resources/spring/spring-tools.xml
new file mode 100644
index 0000000..784de2d
--- /dev/null
+++ b/src/main/resources/spring/spring-tools.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..495e101
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,27 @@
+
+
+ Archetype Created Web Application
+
+
+ userServlet
+ ru.javawebinar.topjava.web.UserServlet
+ 0
+
+
+ userServlet
+ /users
+
+
+
+ mealServlet
+ ru.javawebinar.topjava.web.MealServlet
+ 0
+
+
+ mealServlet
+ /meals
+
+
diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html
new file mode 100644
index 0000000..962ff06
--- /dev/null
+++ b/src/main/webapp/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Codestin Search App
+
+
+Приложение вебинара "Top Java."
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp
new file mode 100644
index 0000000..78331f9
--- /dev/null
+++ b/src/main/webapp/mealList.jsp
@@ -0,0 +1,13 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
+ Codestin Search App
+
+
+Meal list
+
+
+
diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp
new file mode 100644
index 0000000..0ee783c
--- /dev/null
+++ b/src/main/webapp/userList.jsp
@@ -0,0 +1,13 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
+ Codestin Search App
+
+
+User list
+
+
+
diff --git a/src/test/java/ru/javawebinar/topjava/MealTestData.java b/src/test/java/ru/javawebinar/topjava/MealTestData.java
new file mode 100644
index 0000000..e6eddc7
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/MealTestData.java
@@ -0,0 +1,41 @@
+package ru.javawebinar.topjava;
+
+import ru.javawebinar.topjava.matcher.ModelMatcher;
+import ru.javawebinar.topjava.model.UserMeal;
+
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.util.Arrays;
+import java.util.List;
+
+import static java.time.LocalDateTime.of;
+import static ru.javawebinar.topjava.model.BaseEntity.START_SEQ;
+
+/**
+ * GKislin
+ * 13.03.2015.
+ */
+public class MealTestData {
+ public static final int MEAL1_ID = START_SEQ + 2;
+ public static final int ADMIN_MEAL_ID = START_SEQ + 8;
+
+ public static final UserMeal MEAL1 = new UserMeal(MEAL1_ID, LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500);
+ public static final UserMeal MEAL2 = new UserMeal(START_SEQ + 3, LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000);
+ public static final UserMeal MEAL3 = new UserMeal(START_SEQ + 4, LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500);
+ public static final UserMeal MEAL4 = new UserMeal(START_SEQ + 5, LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 500);
+ public static final UserMeal MEAL5 = new UserMeal(START_SEQ + 6, LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 1000);
+ public static final UserMeal MEAL6 = new UserMeal(START_SEQ + 7, LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510);
+ public static final UserMeal ADMIN_MEAL = new UserMeal(ADMIN_MEAL_ID, LocalDateTime.of(2015, Month.JUNE, 1, 14, 0), "Админ-Ланч", 2001);
+
+ public static final List USER_MEALS = Arrays.asList(MEAL6, MEAL5, MEAL4, MEAL3, MEAL2, MEAL1);
+
+ public static UserMeal getCreated() {
+ return new UserMeal(null, of(2015, Month.JUNE, 1, 18, 0), "Созданный ужин", 300);
+ }
+
+ public static UserMeal getUpdated() {
+ return new UserMeal(MEAL1_ID, MEAL1.getDateTime(), "Обновленный завтрак", 200);
+ }
+
+ public static final ModelMatcher MATCHER = new ModelMatcher<>(UserMeal::toString);
+}
diff --git a/src/test/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java
new file mode 100644
index 0000000..305a378
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/SpringMain.java
@@ -0,0 +1,37 @@
+package ru.javawebinar.topjava;
+
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import ru.javawebinar.topjava.model.Role;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.to.UserMealWithExceed;
+import ru.javawebinar.topjava.web.meal.UserMealRestController;
+import ru.javawebinar.topjava.web.user.AdminUserRestController;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * User: gkislin
+ * Date: 22.08.2014
+ */
+public class SpringMain {
+ public static void main(String[] args) {
+ // java 7 Automatic resource management
+ try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml","spring/mock.xml")) {
+ System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames()));
+ AdminUserRestController adminUserController = appCtx.getBean(AdminUserRestController.class);
+ System.out.println(adminUserController.create(new User(1, "userName", "email", "password", Role.ROLE_ADMIN)));
+ System.out.println();
+ UserMealRestController mealController = appCtx.getBean(UserMealRestController.class);
+ List filteredMealsWithExceeded =
+ mealController.getBetween(
+ LocalDate.of(2015, Month.MAY, 30), LocalTime.of(7, 0),
+ LocalDate.of(2015, Month.MAY, 31), LocalTime.of(11, 0));
+ filteredMealsWithExceeded.forEach(System.out::println);
+ }
+ }
+}
diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java
new file mode 100644
index 0000000..6bf625f
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java
@@ -0,0 +1,78 @@
+package ru.javawebinar.topjava;
+
+import ru.javawebinar.topjava.matcher.ModelMatcher;
+import ru.javawebinar.topjava.model.BaseEntity;
+import ru.javawebinar.topjava.model.Role;
+import ru.javawebinar.topjava.model.User;
+
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+
+import static ru.javawebinar.topjava.model.BaseEntity.START_SEQ;
+
+/**
+ * User: gkislin
+ * Date: 26.08.2014
+ */
+public class UserTestData {
+ public static final int USER_ID = START_SEQ;
+ public static final int ADMIN_ID = START_SEQ + 1;
+
+ public static final TestUser USER = new TestUser(BaseEntity.START_SEQ, "User", "user@yandex.ru", "password", true, Role.ROLE_USER);
+ public static final User ADMIN = new TestUser(BaseEntity.START_SEQ + 1, "Admin", "admin@gmail.com", "admin", true, Role.ROLE_ADMIN);
+
+ public static class TestUser extends User {
+
+ public TestUser(User u) {
+ this(u.getId(), u.getName(), u.getEmail(), u.getPassword(), u.isEnabled(), u.getRoles());
+ }
+
+ public TestUser(String name, String email, String password, Role role, Role... roles) {
+ this(null, name, email, password, true, EnumSet.of(role, roles));
+ }
+
+ public TestUser(Integer id, String name, String email, String password, boolean enabled, Role role, Role... roles) {
+ this(id, name, email, password, enabled, EnumSet.of(role, roles));
+ }
+
+ public TestUser(Integer id, String name, String email, String password, boolean enabled, Set roles) {
+ super(id, name, email, password, enabled, roles);
+ }
+
+ public User asUser() {
+ return new User(this);
+ }
+
+ @Override
+ public String toString() {
+ return "User (" +
+ "id=" + id +
+ ", email=" + email +
+ ", name=" + name +
+ ", enabled=" + enabled +
+ ", password=" + password +
+ ", authorities=" + roles +
+ ')';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TestUser that = (TestUser) o;
+
+ return Objects.equals(this.password, that.password)
+ && Objects.equals(this.id, that.id)
+ && Objects.equals(this.name, that.name)
+ && Objects.equals(this.email, that.email)
+ && Objects.equals(this.enabled, that.enabled);
+// && Objects.equals(this.roles, that.roles);
+ }
+ }
+
+ public static final ModelMatcher MATCHER = new ModelMatcher<>(
+ u -> ((u instanceof TestUser) ? (TestUser) u : new TestUser(u)));
+
+}
diff --git a/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java
new file mode 100644
index 0000000..b92c2e4
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java
@@ -0,0 +1,34 @@
+package ru.javawebinar.topjava.matcher;
+
+import org.junit.Assert;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * GKislin
+ * 06.01.2015.
+ *
+ * @param : entity
+ * @param : testEntity, converter result for compare
+ */
+public class ModelMatcher {
+ protected Function entityConverter;
+
+ public ModelMatcher(Function entityConverter) {
+ this.entityConverter = entityConverter;
+ }
+
+ public void assertEquals(T expected, T actual) {
+ Assert.assertEquals(entityConverter.apply(expected), entityConverter.apply(actual));
+ }
+
+ public void assertListEquals(List expected, List actual) {
+ Assert.assertEquals(map(expected, entityConverter), map(actual, entityConverter));
+ }
+
+ public static List map(List list, Function converter) {
+ return list.stream().map(converter).collect(Collectors.toList());
+ }
+}
diff --git a/src/test/java/ru/javawebinar/topjava/repository/mock/MockUserMealRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/MockUserMealRepositoryImpl.java
new file mode 100644
index 0000000..1f0d0c9
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/repository/mock/MockUserMealRepositoryImpl.java
@@ -0,0 +1,54 @@
+package ru.javawebinar.topjava.repository.mock;
+
+import org.springframework.stereotype.Repository;
+import ru.javawebinar.topjava.LoggerWrapper;
+import ru.javawebinar.topjava.MealTestData;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.repository.UserMealRepository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * GKislin
+ * 15.06.2015.
+ */
+@Repository
+public class MockUserMealRepositoryImpl implements UserMealRepository {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(MockUserMealRepositoryImpl.class);
+
+ @Override
+ public boolean delete(int id, int userId) {
+ LOG.info("delete {} for User {}", id, userId);
+ return true;
+ }
+
+ @Override
+ public UserMeal save(UserMeal meal, int userId) {
+ LOG.info("save {} for User {}", meal, userId);
+ return meal;
+ }
+
+ @Override
+ public UserMeal get(int id, int userId) {
+ LOG.info("get {} for User {}", id, userId);
+ return null;
+ }
+
+ @Override
+ public List getAll(int userId) {
+ LOG.info("getAll for User {}", userId);
+ return MealTestData.USER_MEALS;
+ }
+
+ @Override
+ public void deleteAll(int userId) {
+ LOG.info("deleteAll for User {}", userId);
+ }
+
+ @Override
+ public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) {
+ LOG.info("getBetween {} - {} for User {}", startDate, endDate, userId);
+ return MealTestData.USER_MEALS;
+ }
+}
diff --git a/src/test/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java
new file mode 100644
index 0000000..0935c96
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java
@@ -0,0 +1,60 @@
+package ru.javawebinar.topjava.repository.mock;
+
+import org.springframework.stereotype.Repository;
+import ru.javawebinar.topjava.LoggerWrapper;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.repository.UserRepository;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * GKislin
+ * 15.06.2015.
+ */
+@Repository
+public class MockUserRepositoryImpl implements UserRepository {
+ private static final LoggerWrapper LOG = LoggerWrapper.get(MockUserRepositoryImpl.class);
+
+ @PostConstruct
+ public void postConstruct() {
+ LOG.info("+++ PostConstruct");
+ }
+
+ @PreDestroy
+ public void preDestroy() {
+ LOG.info("+++ PreDestroy");
+ }
+
+ @Override
+ public boolean delete(int id) {
+ LOG.info("delete " + id);
+ return id != 0;
+ }
+
+ @Override
+ public User save(User user) {
+ LOG.info("save " + user);
+ return user;
+ }
+
+ @Override
+ public User get(int id) {
+ LOG.info("get " + id);
+ return null;
+ }
+
+ @Override
+ public List getAll() {
+ LOG.info("getAll");
+ return Collections.emptyList();
+ }
+
+ @Override
+ public User getByEmail(String email) {
+ LOG.info("getByEmail " + email);
+ return null;
+ }
+}
diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java
new file mode 100644
index 0000000..743ad91
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java
@@ -0,0 +1,106 @@
+package ru.javawebinar.topjava.service;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlConfig;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import ru.javawebinar.topjava.MealTestData;
+import ru.javawebinar.topjava.model.UserMeal;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.Arrays;
+
+import static ru.javawebinar.topjava.MealTestData.*;
+import static ru.javawebinar.topjava.UserTestData.ADMIN_ID;
+import static ru.javawebinar.topjava.UserTestData.USER_ID;
+
+@ContextConfiguration({
+ "classpath:spring/spring-app.xml",
+ "classpath:spring/spring-db.xml"
+})
+@RunWith(SpringJUnit4ClassRunner.class)
+@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8"))
+@ActiveProfiles("postgres")
+public class UserMealServiceTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Autowired
+ protected UserMealService service;
+
+ @Test
+ public void testDelete() throws Exception {
+ service.delete(MealTestData.MEAL1_ID, USER_ID);
+ MATCHER.assertListEquals(Arrays.asList(MEAL6, MEAL5, MEAL4, MEAL3, MEAL2), service.getAll(USER_ID));
+ }
+
+ // @Test(expected = NotFoundException.class)
+ @Test
+ public void testDeleteNotFound() throws Exception {
+ thrown.expect(NotFoundException.class);
+ service.delete(MEAL1_ID, 1);
+ }
+
+ @Test
+ public void testSave() throws Exception {
+ UserMeal created = getCreated();
+ service.save(created, USER_ID);
+ MATCHER.assertListEquals(Arrays.asList(created, MEAL6, MEAL5, MEAL4, MEAL3, MEAL2, MEAL1), service.getAll(USER_ID));
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ UserMeal actual = service.get(ADMIN_MEAL_ID, ADMIN_ID);
+ MATCHER.assertEquals(ADMIN_MEAL, actual);
+ }
+
+ // @Test(expected = NotFoundException.class)
+ @Test
+ public void testGetNotFound() throws Exception {
+ thrown.expect(NotFoundException.class);
+ service.get(MEAL1_ID, ADMIN_ID);
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ UserMeal updated = getUpdated();
+ service.update(updated, USER_ID);
+ MATCHER.assertEquals(updated, service.get(MEAL1_ID, USER_ID));
+ }
+
+ // @Test(expected = NotFoundException.class)
+ @Test
+ public void testNotFoundUpdate() throws Exception {
+ UserMeal item = service.get(MEAL1_ID, USER_ID);
+ thrown.expect(NotFoundException.class);
+ thrown.expectMessage("Not found entity with id=" + MEAL1_ID);
+ service.update(item, ADMIN_ID);
+ }
+
+ @Test
+ public void testGetAll() throws Exception {
+ MATCHER.assertListEquals(USER_MEALS, service.getAll(USER_ID));
+ }
+
+ @Test
+ public void testGetBetween() throws Exception {
+ MATCHER.assertListEquals(Arrays.asList(MEAL3, MEAL2, MEAL1),
+ service.getBetweenDates(LocalDate.of(2015, Month.MAY, 30), LocalDate.of(2015, Month.MAY, 30), USER_ID));
+ }
+
+ @Test
+ public void testDeleteAll() throws Exception {
+ service.deleteAll(USER_ID);
+ Assert.assertEquals(0, service.getAll(USER_ID).size());
+ }
+}
diff --git a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java
new file mode 100644
index 0000000..23e3c5c
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java
@@ -0,0 +1,91 @@
+package ru.javawebinar.topjava.service;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlConfig;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import ru.javawebinar.topjava.UserTestData.*;
+import ru.javawebinar.topjava.model.Role;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static ru.javawebinar.topjava.UserTestData.*;
+
+@ContextConfiguration({
+ "classpath:spring/spring-app.xml",
+ "classpath:spring/spring-db.xml"
+})
+@RunWith(SpringJUnit4ClassRunner.class)
+@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8"))
+@ActiveProfiles("postgres")
+public class UserServiceTest {
+
+ @Autowired
+ protected UserService service;
+
+ @Before
+ public void setUp() throws Exception {
+ service.evictCache();
+ }
+
+ @Test
+ public void testSave() throws Exception {
+ TestUser tu = new TestUser("New", "new@gmail.com", "newPass", Role.ROLE_USER);
+ User created = service.save(tu.asUser());
+ tu.setId(created.getId());
+ MATCHER.assertListEquals(Arrays.asList(ADMIN, tu, USER), service.getAll());
+ }
+
+ @Test(expected = DataAccessException.class)
+ public void testDuplicateMailSave() throws Exception {
+ service.save(new TestUser("Duplicate", "user@yandex.ru", "newPass", Role.ROLE_USER).asUser());
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ service.delete(USER_ID);
+ MATCHER.assertListEquals(Collections.singletonList(ADMIN), service.getAll());
+ }
+
+ @Test(expected = NotFoundException.class)
+ public void testNotFoundDelete() throws Exception {
+ service.delete(1);
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ User user = service.get(USER_ID);
+ MATCHER.assertEquals(USER, user);
+ }
+
+ @Test
+ public void testGetByEmail() throws Exception {
+ User user = service.getByEmail("user@yandex.ru");
+ MATCHER.assertEquals(USER, user);
+
+ }
+
+ @Test
+ public void testGetAll() throws Exception {
+ List all = service.getAll();
+ MATCHER.assertListEquals(Arrays.asList(ADMIN, USER), all);
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ TestUser updated = new TestUser(USER);
+ updated.setName("UpdatedName");
+ service.update(updated.asUser());
+ MATCHER.assertEquals(updated, service.get(USER_ID));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/javawebinar/topjava/web/mock/UserAdminMockTest.java b/src/test/java/ru/javawebinar/topjava/web/mock/UserAdminMockTest.java
new file mode 100644
index 0000000..bb1fbfb
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/web/mock/UserAdminMockTest.java
@@ -0,0 +1,38 @@
+package ru.javawebinar.topjava.web.mock;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+import ru.javawebinar.topjava.web.user.AdminUserRestController;
+
+import java.util.Arrays;
+
+public class UserAdminMockTest {
+ private static ConfigurableApplicationContext appCtx;
+ private static AdminUserRestController controller;
+
+ @BeforeClass
+ public static void beforeClass() {
+ appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/mock.xml");
+ System.out.println("\n" + Arrays.toString(appCtx.getBeanDefinitionNames()) + "\n");
+ controller = appCtx.getBean(AdminUserRestController.class);
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ appCtx.close();
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ controller.delete(7);
+ }
+
+ @Test(expected = NotFoundException.class)
+ public void testDeleteNotFound() throws Exception {
+ controller.delete(0);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/javawebinar/topjava/web/mock/UserAdminSpringMockTest.java b/src/test/java/ru/javawebinar/topjava/web/mock/UserAdminSpringMockTest.java
new file mode 100644
index 0000000..9b1868c
--- /dev/null
+++ b/src/test/java/ru/javawebinar/topjava/web/mock/UserAdminSpringMockTest.java
@@ -0,0 +1,38 @@
+package ru.javawebinar.topjava.web.mock;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import ru.javawebinar.topjava.model.Role;
+import ru.javawebinar.topjava.model.User;
+import ru.javawebinar.topjava.util.exception.NotFoundException;
+import ru.javawebinar.topjava.web.user.AdminUserRestController;
+
+/**
+ * GKislin
+ * 13.03.2015.
+ */
+@ContextConfiguration({"classpath:spring/spring-app.xml", "classpath:spring/mock.xml"})
+@RunWith(SpringJUnit4ClassRunner.class)
+public class UserAdminSpringMockTest {
+
+ @Autowired
+ private AdminUserRestController controller;
+
+ @Test
+ public void testCreate() throws Exception {
+ controller.create(new User(null, "Name", "email@ya.ru", "password", Role.ROLE_USER));
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ controller.delete(7);
+ }
+
+ @Test(expected = NotFoundException.class)
+ public void testDeleteNotFound() throws Exception {
+ controller.delete(0);
+ }
+}
diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..80c3802
--- /dev/null
+++ b/src/test/resources/logback-test.xml
@@ -0,0 +1,21 @@
+
+
+
+ true
+
+
+
+
+ UTF-8
+ %-5level %logger{0} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/spring/mock.xml b/src/test/resources/spring/mock.xml
new file mode 100644
index 0000000..c7c9f62
--- /dev/null
+++ b/src/test/resources/spring/mock.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file