package io.dropwizard.hibernate;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.Application;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.db.PooledDataSourceFactory;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.dropwizard.testing.ResourceHelpers;
import io.dropwizard.testing.junit.DropwizardAppRule;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.ClassRule;
import org.junit.Test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
public class SubResourcesTest {
public static class TestConfiguration extends Configuration {
DataSourceFactory dataSource = new DataSourceFactory();
TestConfiguration(@JsonProperty("dataSource") DataSourceFactory dataSource) {
this.dataSource = dataSource;
}
}
public static class TestApplication extends Application<TestConfiguration> {
final HibernateBundle<TestConfiguration> hibernate = new HibernateBundle<TestConfiguration>(Person.class, Dog.class) {
@Override
public PooledDataSourceFactory getDataSourceFactory(TestConfiguration configuration) {
return configuration.dataSource;
}
};
@Override
public void initialize(Bootstrap<TestConfiguration> bootstrap) {
bootstrap.addBundle(hibernate);
}
@Override
public void run(TestConfiguration configuration, Environment environment) throws Exception {
final SessionFactory sessionFactory = hibernate.getSessionFactory();
initDatabase(sessionFactory);
environment.jersey().register(new UnitOfWorkApplicationListener("hr-db", sessionFactory));
environment.jersey().register(new PersonResource(new PersonDAO(sessionFactory), new DogDAO(sessionFactory)));
}
private void initDatabase(SessionFactory sessionFactory) {
try (Session session = sessionFactory.openSession()) {
Transaction transaction = session.beginTransaction();
session.createNativeQuery("CREATE TABLE people (name varchar(100) primary key, email varchar(16), birthday timestamp)")
.executeUpdate();
session.createNativeQuery("INSERT INTO people VALUES ('Greg', 'greg@yahooo.com', '1989-02-13')")
.executeUpdate();
session.createNativeQuery("CREATE TABLE dogs (name varchar(100) primary key, owner varchar(100) REFERENCES people(name))")
.executeUpdate();
session.createNativeQuery("INSERT INTO dogs VALUES ('Bello', 'Greg')")
.executeUpdate();
transaction.commit();
}
}
}
@Produces(MediaType.APPLICATION_JSON)
@Path("/people")
public static class PersonResource {
private final PersonDAO personDao;
private final DogResource dogResource;
PersonResource(PersonDAO dao, DogDAO dogDao) {
this.personDao = dao;
this.dogResource = new DogResource(dogDao, personDao);
}
@GET
@Path("{name}")
@UnitOfWork(readOnly = true)
public Optional<Person> find(@PathParam("name") String name) {
return personDao.findByName(name);
}
@POST
@UnitOfWork
public Person save(Person person) {
return personDao.persist(person);
}
@Path("/{ownerName}/dogs")
public DogResource dogResource() {
return dogResource;
}
}
@Produces(MediaType.APPLICATION_JSON)
public static class DogResource {
private final DogDAO dogDAO;
private final PersonDAO personDAO;
DogResource(DogDAO dogDAO, PersonDAO personDAO) {
this.dogDAO = dogDAO;
this.personDAO = personDAO;
}
@GET
// Intentionally no `@UnitOfWork`
public List<Dog> findAll(@PathParam("ownerName") String ownerName) {
return dogDAO.findByOwner(ownerName);
}
@GET
@Path("{dogName}")
@UnitOfWork(readOnly = true)
public Optional<Dog> find(@PathParam("ownerName") String ownerName,
@PathParam("dogName") String dogName) {
return dogDAO.findByOwnerAndName(ownerName, dogName);
}
@POST
@UnitOfWork
public Dog create(@PathParam("ownerName") String ownerName, Dog dog) {
Optional<Person> person = personDAO.findByName(ownerName);
if (!person.isPresent()) {
throw new WebApplicationException(404);
}
dog.setOwner(person.get());
return dogDAO.persist(dog);
}
}
public static class PersonDAO extends AbstractDAO<Person> {
PersonDAO(SessionFactory sessionFactory) {
super(sessionFactory);
}
Optional<Person> findByName(String name) {
return Optional.ofNullable(get(name));
}
}
public static class DogDAO extends AbstractDAO<Dog> {
DogDAO(SessionFactory sessionFactory) {
super(sessionFactory);
}
Optional<Dog> findByOwnerAndName(String ownerName, String dogName) {
return query("SELECT d FROM Dog d WHERE d.owner.name=:owner AND d.name=:name")
.setParameter("owner", ownerName)
.setParameter("name", dogName)
.uniqueResultOptional();
}
List<Dog> findByOwner(String ownerName) {
return query("SELECT d FROM Dog d WHERE d.owner.name=:owner")
.setParameter("owner", ownerName)
.list();
}
}
@ClassRule
public static DropwizardAppRule<TestConfiguration> appRule = new DropwizardAppRule<>(TestApplication.class,
ResourceHelpers.resourceFilePath("hibernate-sub-resource-test.yaml"));
private static String baseUri() {
return "http://localhost:" + appRule.getLocalPort();
}
@Test
public void canReadFromTopResource() throws Exception {
final Person person = appRule.client()
.target(baseUri() + "/people/Greg")
.request()
.get(Person.class);
assertThat(person.getName()).isEqualTo("Greg");
}
@Test
public void canWriteTopResource() throws Exception {
final Person person = appRule.client()
.target(baseUri() + "/people")
.request()
.post(Entity.entity("{\"name\": \"Jason\", \"email\": \"jason@gmail.com\", \"birthday\":637317407000}",
MediaType.APPLICATION_JSON_TYPE), Person.class);
assertThat(person.getName()).isEqualTo("Jason");
}
@Test
public void canReadFromSubResources() throws Exception {
final Dog dog = appRule.client()
.target(baseUri() + "/people/Greg/dogs/Bello")
.request()
.get(Dog.class);
assertThat(dog.getName()).isEqualTo("Bello");
assertThat(dog.getOwner()).isNotNull();
assertThat(dog.getOwner().getName()).isEqualTo("Greg");
}
@Test
public void canWriteSubResource() throws Exception {
final Dog dog = appRule.client()
.target(baseUri() + "/people/Greg/dogs")
.request()
.post(Entity.entity("{\"name\": \"Bandit\"}", MediaType.APPLICATION_JSON_TYPE), Dog.class);
assertThat(dog.getName()).isEqualTo("Bandit");
assertThat(dog.getOwner()).isNotNull();
assertThat(dog.getOwner().getName()).isEqualTo("Greg");
}
@Test
public void errorsAreHandled() throws Exception {
Response response = appRule.client()
.target(baseUri() + "/people/Jim/dogs")
.request()
.post(Entity.entity("{\"name\": \"Bullet\"}", MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
public void noSessionErrorIsRaised() throws Exception {
Response response = appRule.client()
.target(baseUri() + "/people/Greg/dogs")
.request()
.get();
assertThat(response.getStatus()).isEqualTo(500);
}
}