commit
0982f00a61
29
cqrs/README.md
Normal file
29
cqrs/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: CQRS
|
||||
folder: cqrs
|
||||
permalink: /patterns/cqrs/
|
||||
pumlid: 7SPR4a0m3030gt00pR_RH6I8QQFouFgC_TfHb6gkd5Q7FQBx363ub4rYpoMTZKuDrYXqDX37HIuuyCPfPPTDfuuHREhGqBy0NUR0GNzAMYizMtq1
|
||||
categories: Architectural
|
||||
tags:
|
||||
- Java
|
||||
- Difficulty-Intermediate
|
||||
---
|
||||
|
||||
## Intent
|
||||
CQRS Command Query Responsibility Segregation - Separate the query side from the command side.
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
Use the CQRS pattern when
|
||||
|
||||
* you want to scale the queries and commands independently.
|
||||
* you want to use different data models for queries and commands. Useful when dealing with complex domains.
|
||||
* you want to use architectures like event sourcing or task based UI.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/)
|
||||
* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html)
|
||||
* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw)
|
BIN
cqrs/etc/cqrs.png
Normal file
BIN
cqrs/etc/cqrs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 103 KiB |
115
cqrs/etc/cqrs.ucls
Normal file
115
cqrs/etc/cqrs.ucls
Normal file
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<class-diagram version="1.2.0" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
||||
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
||||
<interface id="1" language="java" name="com.iluwatar.cqrs.commandes.ICommandService" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="291" y="-49"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</interface>
|
||||
<class id="2" language="java" name="com.iluwatar.cqrs.commandes.CommandServiceImpl" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="263" width="256" x="170" y="87"/>
|
||||
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<interface id="3" language="java" name="com.iluwatar.cqrs.queries.IQueryService" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="182" width="248" x="176" y="428"/>
|
||||
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</interface>
|
||||
<class id="4" language="java" name="com.iluwatar.cqrs.queries.QueryServiceImpl" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="258" width="253" x="169" y="665"/>
|
||||
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="5" language="java" name="com.iluwatar.cqrs.domain.model.Book" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="326" width="158" x="778" y="-93"/>
|
||||
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="6" language="java" name="com.iluwatar.cqrs.dto.Book" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="219" width="150" x="541" y="607"/>
|
||||
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="7" language="java" name="com.iluwatar.cqrs.domain.model.Author" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="608" y="70"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="8" language="java" name="com.iluwatar.cqrs.dto.Author" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="834" y="719"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="9" language="java" name="com.iluwatar.cqrs.util.HibernateUtil" project="cqrs"
|
||||
file="/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="662" y="412"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<dependency id="10">
|
||||
<end type="SOURCE" refId="4"/>
|
||||
<end type="TARGET" refId="9"/>
|
||||
</dependency>
|
||||
<dependency id="11">
|
||||
<end type="SOURCE" refId="2"/>
|
||||
<end type="TARGET" refId="9"/>
|
||||
</dependency>
|
||||
<realization id="12">
|
||||
<end type="SOURCE" refId="4"/>
|
||||
<end type="TARGET" refId="3"/>
|
||||
</realization>
|
||||
<association id="13">
|
||||
<end type="SOURCE" refId="5" navigable="false">
|
||||
<attribute id="14" name="author"/>
|
||||
<multiplicity id="15" minimum="0" maximum="1"/>
|
||||
</end>
|
||||
<end type="TARGET" refId="7" navigable="true"/>
|
||||
<display labels="true" multiplicity="true"/>
|
||||
</association>
|
||||
<realization id="16">
|
||||
<end type="SOURCE" refId="2"/>
|
||||
<end type="TARGET" refId="1"/>
|
||||
</realization>
|
||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</classifier-display>
|
||||
<association-display labels="true" multiplicity="true"/>
|
||||
</class-diagram>
|
124
cqrs/etc/cqrs.urm.puml
Normal file
124
cqrs/etc/cqrs.urm.puml
Normal file
@ -0,0 +1,124 @@
|
||||
@startuml
|
||||
package com.iluwatar.cqrs.util {
|
||||
class HibernateUtil {
|
||||
- LOGGER : Logger {static}
|
||||
- SESSIONFACTORY : SessionFactory {static}
|
||||
+ HibernateUtil()
|
||||
- buildSessionFactory() : SessionFactory {static}
|
||||
+ getSessionFactory() : SessionFactory {static}
|
||||
}
|
||||
}
|
||||
package com.iluwatar.cqrs.app {
|
||||
class App {
|
||||
+ App()
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
}
|
||||
package com.iluwatar.cqrs.dto {
|
||||
class Author {
|
||||
- email : String
|
||||
- name : String
|
||||
- username : String
|
||||
+ Author()
|
||||
+ Author(name : String, email : String, username : String)
|
||||
+ equals(obj : Object) : boolean
|
||||
+ getEmail() : String
|
||||
+ getName() : String
|
||||
+ getUsername() : String
|
||||
+ hashCode() : int
|
||||
+ toString() : String
|
||||
}
|
||||
class Book {
|
||||
- price : double
|
||||
- title : String
|
||||
+ Book()
|
||||
+ Book(title : String, price : double)
|
||||
+ equals(obj : Object) : boolean
|
||||
+ getPrice() : double
|
||||
+ getTitle() : String
|
||||
+ hashCode() : int
|
||||
+ toString() : String
|
||||
}
|
||||
}
|
||||
package com.iluwatar.cqrs.commandes {
|
||||
class CommandServiceImpl {
|
||||
- sessionFactory : SessionFactory
|
||||
+ CommandServiceImpl()
|
||||
+ authorCreated(username : String, name : String, email : String)
|
||||
+ authorEmailUpdated(username : String, email : String)
|
||||
+ authorNameUpdated(username : String, name : String)
|
||||
+ authorUsernameUpdated(oldUsername : String, newUsername : String)
|
||||
+ bookAddedToAuthor(title : String, price : double, username : String)
|
||||
+ bookPriceUpdated(title : String, price : double)
|
||||
+ bookTitleUpdated(oldTitle : String, newTitle : String)
|
||||
- getAuthorByUsername(username : String) : Author
|
||||
- getBookByTitle(title : String) : Book
|
||||
}
|
||||
interface ICommandService {
|
||||
+ authorCreated(String, String, String) {abstract}
|
||||
+ authorEmailUpdated(String, String) {abstract}
|
||||
+ authorNameUpdated(String, String) {abstract}
|
||||
+ authorUsernameUpdated(String, String) {abstract}
|
||||
+ bookAddedToAuthor(String, double, String) {abstract}
|
||||
+ bookPriceUpdated(String, double) {abstract}
|
||||
+ bookTitleUpdated(String, String) {abstract}
|
||||
}
|
||||
}
|
||||
package com.iluwatar.cqrs.queries {
|
||||
interface IQueryService {
|
||||
+ getAuthorBooks(String) : List<Book> {abstract}
|
||||
+ getAuthorBooksCount(String) : BigInteger {abstract}
|
||||
+ getAuthorByUsername(String) : Author {abstract}
|
||||
+ getAuthorsCount() : BigInteger {abstract}
|
||||
+ getBook(String) : Book {abstract}
|
||||
}
|
||||
class QueryServiceImpl {
|
||||
- sessionFactory : SessionFactory
|
||||
+ QueryServiceImpl()
|
||||
+ getAuthorBooks(username : String) : List<Book>
|
||||
+ getAuthorBooksCount(username : String) : BigInteger
|
||||
+ getAuthorByUsername(username : String) : Author
|
||||
+ getAuthorsCount() : BigInteger
|
||||
+ getBook(title : String) : Book
|
||||
}
|
||||
}
|
||||
package com.iluwatar.cqrs.domain.model {
|
||||
class Author {
|
||||
- email : String
|
||||
- id : long
|
||||
- name : String
|
||||
- username : String
|
||||
# Author()
|
||||
+ Author(username : String, name : String, email : String)
|
||||
+ getEmail() : String
|
||||
+ getId() : long
|
||||
+ getName() : String
|
||||
+ getUsername() : String
|
||||
+ setEmail(email : String)
|
||||
+ setId(id : long)
|
||||
+ setName(name : String)
|
||||
+ setUsername(username : String)
|
||||
+ toString() : String
|
||||
}
|
||||
class Book {
|
||||
- author : Author
|
||||
- id : long
|
||||
- price : double
|
||||
- title : String
|
||||
# Book()
|
||||
+ Book(title : String, price : double, author : Author)
|
||||
+ getAuthor() : Author
|
||||
+ getId() : long
|
||||
+ getPrice() : double
|
||||
+ getTitle() : String
|
||||
+ setAuthor(author : Author)
|
||||
+ setId(id : long)
|
||||
+ setPrice(price : double)
|
||||
+ setTitle(title : String)
|
||||
+ toString() : String
|
||||
}
|
||||
}
|
||||
Book --> "-author" Author
|
||||
CommandServiceImpl ..|> ICommandService
|
||||
QueryServiceImpl ..|> IQueryService
|
||||
@enduml
|
42
cqrs/pom.xml
Normal file
42
cqrs/pom.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- The MIT License Copyright (c) 2014-2016 Ilkka Seppälä Permission is
|
||||
hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
and associated documentation files (the "Software"), to deal in the Software
|
||||
without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions: The above copyright notice and this
|
||||
permission notice shall be included in all copies or substantial portions
|
||||
of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE. -->
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.17.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>cqrs</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
95
cqrs/src/main/java/com/iluwatar/cqrs/app/App.java
Normal file
95
cqrs/src/main/java/com/iluwatar/cqrs/app/App.java
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.cqrs.app;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.iluwatar.cqrs.commandes.CommandServiceImpl;
|
||||
import com.iluwatar.cqrs.commandes.ICommandService;
|
||||
import com.iluwatar.cqrs.dto.Author;
|
||||
import com.iluwatar.cqrs.dto.Book;
|
||||
import com.iluwatar.cqrs.queries.IQueryService;
|
||||
import com.iluwatar.cqrs.queries.QueryServiceImpl;
|
||||
import com.iluwatar.cqrs.util.HibernateUtil;
|
||||
|
||||
/**
|
||||
* CQRS : Command Query Responsibility Segregation. A pattern used to separate query services from commands or writes
|
||||
* services. The pattern is very simple but it has many consequences. For example, it can be used to tackle down a
|
||||
* complex domain, or to use other architectures that were hard to implement with the classical way.
|
||||
*
|
||||
* This implementation is an example of managing books and authors in a library. The persistence of books and authors is
|
||||
* done according to the CQRS architecture. A command side that deals with a data model to persist(insert,update,delete)
|
||||
* objects to a database. And a query side that uses native queries to get data from the database and return objects as
|
||||
* DTOs (Data transfer Objects).
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args
|
||||
* command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
ICommandService commands = new CommandServiceImpl();
|
||||
|
||||
// Create Authors and Books using CommandService
|
||||
commands.authorCreated("eEvans", "Eric Evans", "eEvans@email.com");
|
||||
commands.authorCreated("jBloch", "Joshua Bloch", "jBloch@email.com");
|
||||
commands.authorCreated("mFowler", "Martin Fowler", "mFowler@email.com");
|
||||
|
||||
commands.bookAddedToAuthor("Domain-Driven Design", 60.08, "eEvans");
|
||||
commands.bookAddedToAuthor("Effective Java", 40.54, "jBloch");
|
||||
commands.bookAddedToAuthor("Java Puzzlers", 39.99, "jBloch");
|
||||
commands.bookAddedToAuthor("Java Concurrency in Practice", 29.40, "jBloch");
|
||||
commands.bookAddedToAuthor("Patterns of Enterprise Application Architecture", 54.01, "mFowler");
|
||||
commands.bookAddedToAuthor("Domain Specific Languages", 48.89, "mFowler");
|
||||
commands.authorNameUpdated("eEvans", "Eric J. Evans");
|
||||
|
||||
IQueryService queries = new QueryServiceImpl();
|
||||
|
||||
// Query the database using QueryService
|
||||
Author nullAuthor = queries.getAuthorByUsername("username");
|
||||
Author eEvans = queries.getAuthorByUsername("eEvans");
|
||||
BigInteger jBlochBooksCount = queries.getAuthorBooksCount("jBloch");
|
||||
BigInteger authorsCount = queries.getAuthorsCount();
|
||||
Book dddBook = queries.getBook("Domain-Driven Design");
|
||||
List<Book> jBlochBooks = queries.getAuthorBooks("jBloch");
|
||||
|
||||
LOGGER.info("Author username : {}", nullAuthor);
|
||||
LOGGER.info("Author eEvans : {}", eEvans);
|
||||
LOGGER.info("jBloch number of books : {}", jBlochBooksCount);
|
||||
LOGGER.info("Number of authors : {}", authorsCount);
|
||||
LOGGER.info("DDD book : {}", dddBook);
|
||||
LOGGER.info("jBloch books : {}", jBlochBooks);
|
||||
|
||||
HibernateUtil.getSessionFactory().close();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package com.iluwatar.cqrs.commandes;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.iluwatar.cqrs.domain.model.Author;
|
||||
import com.iluwatar.cqrs.domain.model.Book;
|
||||
import com.iluwatar.cqrs.util.HibernateUtil;
|
||||
|
||||
/**
|
||||
* This class is an implementation of {@link ICommandService} interface. It uses Hibernate as an api for persistence.
|
||||
*
|
||||
*/
|
||||
public class CommandServiceImpl implements ICommandService {
|
||||
|
||||
private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||
|
||||
private Author getAuthorByUsername(String username) {
|
||||
Author author = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
Query query = session.createQuery("from Author where username=:username");
|
||||
query.setParameter("username", username);
|
||||
author = (Author) query.uniqueResult();
|
||||
}
|
||||
if (author == null) {
|
||||
HibernateUtil.getSessionFactory().close();
|
||||
throw new NullPointerException("Author " + username + " doesn't exist!");
|
||||
}
|
||||
return author;
|
||||
}
|
||||
|
||||
private Book getBookByTitle(String title) {
|
||||
Book book = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
Query query = session.createQuery("from Book where title=:title");
|
||||
query.setParameter("title", title);
|
||||
book = (Book) query.uniqueResult();
|
||||
}
|
||||
if (book == null) {
|
||||
HibernateUtil.getSessionFactory().close();
|
||||
throw new NullPointerException("Book " + title + " doesn't exist!");
|
||||
}
|
||||
return book;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorCreated(String username, String name, String email) {
|
||||
Author author = new Author(username, name, email);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.save(author);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bookAddedToAuthor(String title, double price, String username) {
|
||||
Author author = getAuthorByUsername(username);
|
||||
Book book = new Book(title, price, author);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.save(book);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorNameUpdated(String username, String name) {
|
||||
Author author = getAuthorByUsername(username);
|
||||
author.setName(name);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.update(author);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorUsernameUpdated(String oldUsername, String newUsername) {
|
||||
Author author = getAuthorByUsername(oldUsername);
|
||||
author.setUsername(newUsername);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.update(author);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorEmailUpdated(String username, String email) {
|
||||
Author author = getAuthorByUsername(username);
|
||||
author.setEmail(email);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.update(author);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bookTitleUpdated(String oldTitle, String newTitle) {
|
||||
Book book = getBookByTitle(oldTitle);
|
||||
book.setTitle(newTitle);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.update(book);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bookPriceUpdated(String title, double price) {
|
||||
Book book = getBookByTitle(title);
|
||||
book.setPrice(price);
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
session.beginTransaction();
|
||||
session.update(book);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.iluwatar.cqrs.commandes;
|
||||
|
||||
/**
|
||||
* This interface represents the commands of the CQRS pattern
|
||||
*
|
||||
*/
|
||||
public interface ICommandService {
|
||||
|
||||
void authorCreated(String username, String name, String email);
|
||||
|
||||
void bookAddedToAuthor(String title, double price, String username);
|
||||
|
||||
void authorNameUpdated(String username, String name);
|
||||
|
||||
void authorUsernameUpdated(String oldUsername, String newUsername);
|
||||
|
||||
void authorEmailUpdated(String username, String email);
|
||||
|
||||
void bookTitleUpdated(String oldTitle, String newTitle);
|
||||
|
||||
void bookPriceUpdated(String title, double price);
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package com.iluwatar.cqrs.domain.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* This is an Author entity. It is used by Hibernate for persistence.
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
public class Author {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private long id;
|
||||
private String username;
|
||||
private String name;
|
||||
private String email;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param username
|
||||
* username of the author
|
||||
* @param name
|
||||
* name of the author
|
||||
* @param email
|
||||
* email of the author
|
||||
*/
|
||||
public Author(String username, String name, String email) {
|
||||
super();
|
||||
this.username = username;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
protected Author() {
|
||||
super();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Author [name=" + name + ", email=" + email + "]";
|
||||
}
|
||||
|
||||
}
|
80
cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java
Normal file
80
cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java
Normal file
@ -0,0 +1,80 @@
|
||||
package com.iluwatar.cqrs.domain.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
/**
|
||||
* This is a Book entity. It is used by Hibernate for persistence. Many books can be written by one {@link Author}
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
public class Book {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private long id;
|
||||
private String title;
|
||||
private double price;
|
||||
@ManyToOne
|
||||
private Author author;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param title
|
||||
* title of the book
|
||||
* @param price
|
||||
* price of the book
|
||||
* @param author
|
||||
* author of the book
|
||||
*/
|
||||
public Book(String title, double price, Author author) {
|
||||
super();
|
||||
this.title = title;
|
||||
this.price = price;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
protected Book() {
|
||||
super();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Author author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Book [title=" + title + ", price=" + price + ", author=" + author + "]";
|
||||
}
|
||||
|
||||
}
|
71
cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java
Normal file
71
cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java
Normal file
@ -0,0 +1,71 @@
|
||||
package com.iluwatar.cqrs.dto;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* This is a DTO (Data Transfer Object) author, contains only useful information to be returned
|
||||
*
|
||||
*/
|
||||
public class Author {
|
||||
|
||||
private String name;
|
||||
private String email;
|
||||
private String username;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* name of the author
|
||||
* @param email
|
||||
* email of the author
|
||||
* @param username
|
||||
* username of the author
|
||||
*/
|
||||
public Author(String name, String email, String username) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public Author() {
|
||||
super();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuthorDTO [name=" + name + ", email=" + email + ", username=" + username + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(username, name, email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Author)) {
|
||||
return false;
|
||||
}
|
||||
Author other = (Author) obj;
|
||||
return username.equals(other.getUsername()) && email.equals(other.getEmail()) && name.equals(other.getName());
|
||||
|
||||
}
|
||||
|
||||
}
|
62
cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java
Normal file
62
cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java
Normal file
@ -0,0 +1,62 @@
|
||||
package com.iluwatar.cqrs.dto;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* This is a DTO (Data Transfer Object) book, contains only useful information to be returned
|
||||
*
|
||||
*/
|
||||
public class Book {
|
||||
|
||||
private String title;
|
||||
private double price;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param title
|
||||
* title of the book
|
||||
* @param price
|
||||
* price of the book
|
||||
*/
|
||||
public Book(String title, double price) {
|
||||
super();
|
||||
this.title = title;
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public Book() {
|
||||
super();
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookDTO [title=" + title + ", price=" + price + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(title, price);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Book)) {
|
||||
return false;
|
||||
}
|
||||
Book book = (Book) obj;
|
||||
return title.equals(book.getTitle()) && price == book.getPrice();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.iluwatar.cqrs.queries;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import com.iluwatar.cqrs.dto.Author;
|
||||
import com.iluwatar.cqrs.dto.Book;
|
||||
|
||||
/**
|
||||
*
|
||||
* This interface represents the query methods of the CQRS pattern
|
||||
*
|
||||
*/
|
||||
public interface IQueryService {
|
||||
|
||||
Author getAuthorByUsername(String username);
|
||||
|
||||
Book getBook(String title);
|
||||
|
||||
List<Book> getAuthorBooks(String username);
|
||||
|
||||
BigInteger getAuthorBooksCount(String username);
|
||||
|
||||
BigInteger getAuthorsCount();
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package com.iluwatar.cqrs.queries;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.SQLQuery;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.transform.Transformers;
|
||||
|
||||
import com.iluwatar.cqrs.dto.Author;
|
||||
import com.iluwatar.cqrs.dto.Book;
|
||||
import com.iluwatar.cqrs.util.HibernateUtil;
|
||||
|
||||
/**
|
||||
* This class is an implementation of {@link IQueryService}. It uses Hibernate native queries to return DTOs from the
|
||||
* database.
|
||||
*
|
||||
*/
|
||||
public class QueryServiceImpl implements IQueryService {
|
||||
|
||||
private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||
|
||||
@Override
|
||||
public Author getAuthorByUsername(String username) {
|
||||
Author authorDTo = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
SQLQuery sqlQuery = session
|
||||
.createSQLQuery("SELECT a.username as \"username\", a.name as \"name\", a.email as \"email\""
|
||||
+ "FROM Author a where a.username=:username");
|
||||
sqlQuery.setParameter("username", username);
|
||||
authorDTo = (Author) sqlQuery.setResultTransformer(Transformers.aliasToBean(Author.class)).uniqueResult();
|
||||
}
|
||||
return authorDTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book getBook(String title) {
|
||||
Book bookDTo = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
SQLQuery sqlQuery = session
|
||||
.createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + " FROM Book b where b.title=:title");
|
||||
sqlQuery.setParameter("title", title);
|
||||
bookDTo = (Book) sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).uniqueResult();
|
||||
}
|
||||
return bookDTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> getAuthorBooks(String username) {
|
||||
List<Book> bookDTos = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
SQLQuery sqlQuery = session.createSQLQuery("SELECT b.title as \"title\", b.price as \"price\""
|
||||
+ " FROM Author a , Book b where b.author_id = a.id and a.username=:username");
|
||||
sqlQuery.setParameter("username", username);
|
||||
bookDTos = sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).list();
|
||||
}
|
||||
return bookDTos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getAuthorBooksCount(String username) {
|
||||
BigInteger bookcount = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
SQLQuery sqlQuery = session.createSQLQuery(
|
||||
"SELECT count(b.title)" + " FROM Book b, Author a where b.author_id = a.id and a.username=:username");
|
||||
sqlQuery.setParameter("username", username);
|
||||
bookcount = (BigInteger) sqlQuery.uniqueResult();
|
||||
}
|
||||
return bookcount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getAuthorsCount() {
|
||||
BigInteger authorcount = null;
|
||||
try (Session session = sessionFactory.openSession()) {
|
||||
SQLQuery sqlQuery = session.createSQLQuery("SELECT count(id) from Author");
|
||||
authorcount = (BigInteger) sqlQuery.uniqueResult();
|
||||
}
|
||||
return authorcount;
|
||||
}
|
||||
|
||||
}
|
36
cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java
Normal file
36
cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.iluwatar.cqrs.util;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class simply returns one instance of {@link SessionFactory} initialized when the application is started
|
||||
*
|
||||
*/
|
||||
public class HibernateUtil {
|
||||
|
||||
private static final SessionFactory SESSIONFACTORY = buildSessionFactory();
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HibernateUtil.class);
|
||||
|
||||
private static SessionFactory buildSessionFactory() {
|
||||
|
||||
// configures settings from hibernate.cfg.xml
|
||||
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
|
||||
try {
|
||||
return new MetadataSources(registry).buildMetadata().buildSessionFactory();
|
||||
} catch (Exception ex) {
|
||||
StandardServiceRegistryBuilder.destroy(registry);
|
||||
LOGGER.error("Initial SessionFactory creation failed." + ex);
|
||||
throw new ExceptionInInitializerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static SessionFactory getSessionFactory() {
|
||||
return SESSIONFACTORY;
|
||||
}
|
||||
|
||||
}
|
15
cqrs/src/main/resources/hibernate.cfg.xml
Normal file
15
cqrs/src/main/resources/hibernate.cfg.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE hibernate-configuration SYSTEM
|
||||
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
|
||||
|
||||
<hibernate-configuration>
|
||||
<session-factory>
|
||||
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
|
||||
<property name="connection.driver_class">org.h2.Driver</property>
|
||||
<property name="connection.url">jdbc:h2:mem:test</property>
|
||||
<property name="connection.username">sa</property>
|
||||
<property name="hbm2ddl.auto">create</property>
|
||||
<mapping class="com.iluwatar.cqrs.domain.model.Author" />
|
||||
<mapping class="com.iluwatar.cqrs.domain.model.Book" />
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
13
cqrs/src/main/resources/logback.xml
Normal file
13
cqrs/src/main/resources/logback.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
98
cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java
Normal file
98
cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java
Normal file
@ -0,0 +1,98 @@
|
||||
package com.iluwatar.cqrs;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.iluwatar.cqrs.commandes.CommandServiceImpl;
|
||||
import com.iluwatar.cqrs.commandes.ICommandService;
|
||||
import com.iluwatar.cqrs.dto.Author;
|
||||
import com.iluwatar.cqrs.dto.Book;
|
||||
import com.iluwatar.cqrs.queries.IQueryService;
|
||||
import com.iluwatar.cqrs.queries.QueryServiceImpl;
|
||||
|
||||
/**
|
||||
* Integration test of IQueryService and ICommandService with h2 data
|
||||
*
|
||||
*/
|
||||
public class IntegrationTest {
|
||||
|
||||
private static IQueryService queryService;
|
||||
private static ICommandService commandService;
|
||||
|
||||
@BeforeClass
|
||||
public static void initialize() {
|
||||
commandService = new CommandServiceImpl();
|
||||
queryService = new QueryServiceImpl();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void populateDatabase() {
|
||||
// create first author1
|
||||
commandService.authorCreated("username1", "name1", "email1");
|
||||
|
||||
// create author1 and update all its data
|
||||
commandService.authorCreated("username2", "name2", "email2");
|
||||
commandService.authorEmailUpdated("username2", "new_email2");
|
||||
commandService.authorNameUpdated("username2", "new_name2");
|
||||
commandService.authorUsernameUpdated("username2", "new_username2");
|
||||
|
||||
// add book1 to author1
|
||||
commandService.bookAddedToAuthor("title1", 10, "username1");
|
||||
|
||||
// add book2 to author1 and update all its data
|
||||
commandService.bookAddedToAuthor("title2", 20, "username1");
|
||||
commandService.bookPriceUpdated("title2", 30);
|
||||
commandService.bookTitleUpdated("title2", "new_title2");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthorByUsername() {
|
||||
Author author = queryService.getAuthorByUsername("username1");
|
||||
assertEquals("username1", author.getUsername());
|
||||
assertEquals("name1", author.getName());
|
||||
assertEquals("email1", author.getEmail());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUpdatedAuthorByUsername() {
|
||||
Author author = queryService.getAuthorByUsername("new_username2");
|
||||
Author expectedAuthor = new Author("new_name2", "new_email2", "new_username2");
|
||||
assertEquals(expectedAuthor, author);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBook() {
|
||||
Book book = queryService.getBook("title1");
|
||||
assertEquals("title1", book.getTitle());
|
||||
assertEquals(10, book.getPrice(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthorBooks() {
|
||||
List<Book> books = queryService.getAuthorBooks("username1");
|
||||
assertTrue(books.size() == 2);
|
||||
assertTrue(books.contains(new Book("title1", 10)));
|
||||
assertTrue(books.contains(new Book("new_title2", 30)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthorBooksCount() {
|
||||
BigInteger bookCount = queryService.getAuthorBooksCount("username1");
|
||||
assertEquals(new BigInteger("2"), bookCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthorsCount() {
|
||||
BigInteger authorCount = queryService.getAuthorsCount();
|
||||
assertEquals(new BigInteger("2"), authorCount);
|
||||
}
|
||||
|
||||
}
|
15
cqrs/src/test/resources/hibernate.cfg.xml
Normal file
15
cqrs/src/test/resources/hibernate.cfg.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE hibernate-configuration SYSTEM
|
||||
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
|
||||
|
||||
<hibernate-configuration>
|
||||
<session-factory>
|
||||
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
|
||||
<property name="connection.driver_class">org.h2.Driver</property>
|
||||
<property name="connection.url">jdbc:h2:mem:test</property>
|
||||
<property name="connection.username">sa</property>
|
||||
<property name="hbm2ddl.auto">create</property>
|
||||
<mapping class="com.iluwatar.cqrs.domain.model.Author" />
|
||||
<mapping class="com.iluwatar.cqrs.domain.model.Book" />
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
13
cqrs/src/test/resources/logback.xml
Normal file
13
cqrs/src/test/resources/logback.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
Loading…
x
Reference in New Issue
Block a user