-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
31 changed files
with
2,071 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Lab 07 - Blocking lab | ||
|
||
So far we have been working with CPU bound code. We have not had to perform any kind of synchronous or blocking actions. | ||
Ratpack is asynchronous and non-blocking from the ground up. Ratpack's APIs are marked as `ratpack.api.NonBlocking` where | ||
appropriate to denote the API's non-blocking and asynchronous nature. | ||
|
||
In the real world our existing libraries tend to be blocking and synchronous like the JDBC library. | ||
|
||
Ratpack uses a much smaller set of Threads to manage HTTP Request handling, a single thread could be responsible for handling | ||
hundreds of active connections. If you perform a blocking action one of Ratpack's main compute threads you will impede | ||
throughput and prevent other requests from being processed until the blocking code completes. | ||
|
||
Ratpack provides a great utility for integrating synchronous/blocking code with Ratpack's Execution Model via | ||
`ratpack.exec.Blocking`. This `Blocking` utility allows users to specify blocking code that will inform Ratpack to | ||
execute the blocking code on Ratpack's blocking scheduler. | ||
|
||
Ratpack provides two constructs for representing an asynchronous units of work: `ratpack.exec.Promise` and `ratpack.exec.Operation`. | ||
|
||
The `Blocking` utility creates `Promise` and `Operation` from user supplied code which can then be further mapped or consumed. | ||
|
||
|
||
To complete this lab you will need to implement the `DefaultBookRepository` to perform blocking database calls. | ||
This lab provides generated jOOQ library that specifies a typed representation of the `book` table. | ||
|
||
The database connection to an H2 in-memory database is provided via the `ratpack.h2.H2Module` and connection pooling is | ||
made available through `ratpack.hikari.HikariModule`. | ||
|
||
## This lab covers | ||
|
||
* Working with synchronous/blocking libraries | ||
* Working with Promises and Operations | ||
* Working with Blocking api | ||
* Working with Ratpack's integration with H2 and Hikari | ||
* Parsing incoming JSON | ||
* Rendering a custom object with a different content type depending on what has been requested | ||
|
||
## Sign Posts | ||
|
||
`ratpack.exec.Promise` | ||
|
||
`ratpack.exec.Operation` | ||
|
||
`ratpack.exec.Blocking` | ||
|
||
`ratpack.hikari.HikariModule` | ||
|
||
`ratpack.guice.ConfigurableModule` | ||
|
||
`ratpack.handling.Context#clientError(int)` | ||
|
||
`ratpack.jackson.Jackson.json(Object)` | ||
|
||
`ratpack.handling.Context#parse(Class)` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import java.nio.file.Paths | ||
|
||
buildscript { | ||
repositories { | ||
mavenLocal() | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
classpath 'org.jooq:jooq-codegen:3.7.0' | ||
classpath 'com.h2database:h2:1.4.190' | ||
} | ||
} | ||
|
||
dependencies { | ||
compile 'org.jooq:jooq:3.7.0' | ||
compile ratpack.dependency('guice') | ||
compile ratpack.dependency('hikari') | ||
compile ratpack.dependency('h2') | ||
} | ||
|
||
task generateJooq(group: 'Lab 07 Utilities', description: 'Generates jOOQ library from src/main/resources.init.sql for this lab') << { | ||
// Use your favourite XML builder to construct the code generation configuration file | ||
// ---------------------------------------------------------------------------------- | ||
def writer = new StringWriter() | ||
String initSql = Paths.get(projectDir.toString()).resolve('src/main/resources/init.sql').toString().replaceAll('\\\\', '/') | ||
def xml = new groovy.xml.MarkupBuilder(writer) | ||
.configuration('xmlns': 'http://www.jooq.org/xsd/jooq-codegen-3.7.0.xsd') { | ||
jdbc() { | ||
driver('org.h2.Driver') | ||
url("jdbc:h2:mem:lab07;MODE=MySQL;INIT=RUNSCRIPT FROM '$initSql'") | ||
user('sa') | ||
password('') | ||
} | ||
generator() { | ||
database() { | ||
inputSchema('lab07') | ||
} | ||
generate() { | ||
} | ||
target() { | ||
packageName('lab07.jooq') | ||
directory("$projectDir/src/main/java") | ||
} | ||
} | ||
} | ||
|
||
// Run the code generator | ||
// ---------------------- | ||
org.jooq.util.GenerationTool.generate( | ||
javax.xml.bind.JAXB.unmarshal(new StringReader(writer.toString()), org.jooq.util.jaxb.Configuration.class) | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package lab07; | ||
|
||
import java.math.BigDecimal; | ||
|
||
public class Book { | ||
private String isbn; | ||
private long quantity; | ||
private BigDecimal price; | ||
private String title; | ||
private String author; | ||
private String publisher; | ||
|
||
public String getIsbn() { | ||
return isbn; | ||
} | ||
|
||
public void setIsbn(String isbn) { | ||
this.isbn = isbn; | ||
} | ||
|
||
public long getQuantity() { | ||
return quantity; | ||
} | ||
|
||
public void setQuantity(long quantity) { | ||
this.quantity = quantity; | ||
} | ||
|
||
public BigDecimal getPrice() { | ||
return price; | ||
} | ||
|
||
public void setPrice(BigDecimal price) { | ||
this.price = price; | ||
} | ||
|
||
public String getTitle() { | ||
return title; | ||
} | ||
|
||
public void setTitle(String title) { | ||
this.title = title; | ||
} | ||
|
||
public String getAuthor() { | ||
return author; | ||
} | ||
|
||
public void setAuthor(String author) { | ||
this.author = author; | ||
} | ||
|
||
public String getPublisher() { | ||
return publisher; | ||
} | ||
|
||
public void setPublisher(String publisher) { | ||
this.publisher = publisher; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package lab07; | ||
|
||
import ratpack.exec.Operation; | ||
import ratpack.exec.Promise; | ||
|
||
import java.util.List; | ||
|
||
public interface BookRepository { | ||
Operation addBook(Book book); | ||
Promise<List<Book>> getBooks(); | ||
Promise<Book> getBook(String isbn); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package lab07; | ||
|
||
import ratpack.exec.Operation; | ||
import ratpack.exec.Promise; | ||
|
||
import java.util.List; | ||
|
||
public interface BookService { | ||
Operation addBook(Book book); | ||
Promise<List<Book>> getBooks(); | ||
Promise<Book> getBook(String isbn); | ||
} |
56 changes: 56 additions & 0 deletions
56
lab-07-answer/src/main/java/lab07/DefaultBookRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package lab07; | ||
|
||
import com.google.inject.Inject; | ||
import org.jooq.DSLContext; | ||
import org.jooq.SQLDialect; | ||
import org.jooq.impl.DSL; | ||
import ratpack.exec.Blocking; | ||
import ratpack.exec.Operation; | ||
import ratpack.exec.Promise; | ||
|
||
import javax.sql.DataSource; | ||
import java.util.List; | ||
|
||
import static lab07.jooq.tables.Book.BOOK; | ||
|
||
public class DefaultBookRepository implements BookRepository { | ||
|
||
private final DSLContext create; | ||
|
||
@Inject | ||
public DefaultBookRepository(DataSource ds) { | ||
create = DSL.using(ds, SQLDialect.MYSQL); | ||
} | ||
|
||
@Override | ||
public Operation addBook(Book book) { | ||
// TODO - Implement addBook function | ||
// Hint - checkout Blocking#op(Block) to see how to integrate blocking code with Ratpack | ||
// Hint - checkout DSLContext#newRecord(Table, Object) | ||
// Hint - lab07.jooq.tables.Book.BOOK is the repesentation for the underlying `book` table | ||
return Blocking.op(() -> create.newRecord(BOOK, book).store()); | ||
} | ||
|
||
@Override | ||
public Promise<List<Book>> getBooks() { | ||
// TODO - Implement getBooks function | ||
// Hint - checkout Blocking#get(Block) to see how to integrate blocking code with Ratpack | ||
// Hint - lab07.jooq.tables.Book.BOOK is the repesentation for the underlying `book` table | ||
// Hint - checkout DSLContext#select() and ResultQuery#fetchInto(Class) | ||
return Blocking.get(() -> | ||
create.select().from(BOOK).fetchInto(Book.class) | ||
); | ||
} | ||
|
||
@Override | ||
public Promise<Book> getBook(String isbn) { | ||
// TODO - Implement getBooks function | ||
// Hint - checkout Blocking#get(Block) to see how to integrate blocking code with Ratpack | ||
// Hint - lab07.jooq.tables.Book.BOOK is the repesentation for the underlying `book` table | ||
// Hint - checkout SelectWhereStep#where(Condition...) and ResultQuery#fetchOneInto(Class) | ||
return Blocking.get(() -> | ||
create.select().from(BOOK).where(BOOK.ISBN.equal(isbn)).fetchOneInto(Book.class) | ||
); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package lab07; | ||
|
||
import ratpack.exec.Operation; | ||
import ratpack.exec.Promise; | ||
|
||
import javax.inject.Inject; | ||
import java.util.List; | ||
|
||
public class DefaultBookService implements BookService { | ||
final private BookRepository repository; | ||
|
||
@Inject | ||
public DefaultBookService(BookRepository bookRepository) { | ||
this.repository = bookRepository; | ||
} | ||
|
||
|
||
@Override | ||
public Operation addBook(Book book) { | ||
return repository.addBook(book); | ||
} | ||
|
||
@Override | ||
public Promise<List<Book>> getBooks() { | ||
return repository.getBooks(); | ||
} | ||
|
||
@Override | ||
public Promise<Book> getBook(String isbn) { | ||
return repository.getBook(isbn); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package lab07; | ||
|
||
import com.google.common.collect.Maps; | ||
import ratpack.guice.Guice; | ||
import ratpack.h2.H2Module; | ||
import ratpack.hikari.HikariModule; | ||
import ratpack.jackson.Jackson; | ||
import ratpack.server.RatpackServer; | ||
|
||
import java.util.Map; | ||
|
||
public class Lab07 { | ||
public static void main(String[] args) throws Exception { | ||
RatpackServer.start(ratpackServerSpec -> ratpackServerSpec | ||
.registry(Guice.registry(bindingsSpec -> bindingsSpec | ||
.module(new H2Module("sa", "", "jdbc:h2:mem:lab07;MODE=MySQL")) | ||
.module(HikariModule.class, hikariConfig -> { | ||
hikariConfig.addDataSourceProperty("user", "sa"); | ||
hikariConfig.addDataSourceProperty("password", ""); | ||
hikariConfig.addDataSourceProperty("URL", "jdbc:h2:mem:lab07;INIT=RUNSCRIPT FROM 'classpath:init.sql'"); | ||
hikariConfig.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); | ||
}) | ||
.bind(BookRepository.class, DefaultBookRepository.class) | ||
.bind(BookService.class, DefaultBookService.class) | ||
)) | ||
.handlers(chain -> chain | ||
.prefix("api/book", apiChain -> apiChain | ||
.get(":isbn", ctx -> { | ||
BookService bookService = ctx.get(BookService.class); | ||
String isbn = ctx.getPathTokens().get("isbn"); | ||
// Hint - Checkout ratpack.exec.Promise.then(Action) | ||
// Hint - Use Ratpack's Jackson integration to render the Promised json | ||
// If book doesn't exist return 404 | ||
bookService | ||
.getBook(isbn) | ||
.onNull(() -> ctx.clientError(404)) | ||
.map(Jackson::json) | ||
.then(ctx::render); | ||
}) | ||
.all(ctx -> { | ||
BookService bookService = ctx.get(BookService.class); | ||
ctx.byMethod(byMethodSpec -> byMethodSpec | ||
.get(() -> | ||
// Render the promised list of books as json | ||
// Hint - Checkout ratpack.exec.Promise.then(Action) | ||
// Hint - Use Ratpack's Jackson integration to render the Promised json | ||
bookService.getBooks().map(Jackson::json).then(ctx::render) | ||
) | ||
.post(() -> | ||
// Parse incoming json, store book, then return {"message":"success"} | ||
// Hint - Checkout ratpack.handling.Context#parse(Class) | ||
ctx.parse(Book.class) | ||
.flatMap(book -> bookService | ||
.addBook(book) | ||
.map(() -> { | ||
Map<String, String> result = Maps.newHashMap(); | ||
result.put("message", "success"); | ||
return result; | ||
})) | ||
.map(Jackson::json) | ||
.then(ctx::render) | ||
) | ||
); | ||
}) | ||
) | ||
) | ||
); | ||
} | ||
} |
Oops, something went wrong.