1 package com.atlassian.activeobjects.test.model;
2
3 import com.atlassian.activeobjects.external.ActiveObjects;
4 import com.atlassian.activeobjects.test.TestActiveObjects;
5 import com.google.common.base.Function;
6 import com.google.common.base.Joiner;
7 import com.google.common.base.Predicate;
8 import com.google.common.base.Supplier;
9 import com.google.common.base.Suppliers;
10 import com.google.common.collect.ImmutableList;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.Iterables;
13 import net.java.ao.EntityManager;
14 import net.java.ao.RawEntity;
15 import org.apache.commons.io.IOUtils;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.text.ParseException;
22 import java.text.SimpleDateFormat;
23 import java.util.Date;
24 import java.util.Locale;
25 import java.util.TimeZone;
26
27 import static com.google.common.base.Preconditions.checkNotNull;
28 import static com.google.common.collect.Collections2.transform;
29 import static com.google.common.collect.Lists.newArrayList;
30 import static org.junit.Assert.assertEquals;
31
32 public final class Model {
33 private static final String DATE_FORMAT = "MMM d, yyyy";
34
35 private static final String BRIAN_GOETZ = "Brian Goetz";
36 private static final String TIM_PEIERLS = "Tim Peierls";
37 private static final String JOSHUA_BLOCH = "Joshua Bloch";
38 private static final String JOSEPH_BOWBEER = "Joseph Bowbeer";
39 private static final String DOUG_LEA = "Doug Lea";
40 private static final String DAVID_HOLMES = "David Holmes";
41 private static final String MARTIN_ODERSKY = "Martin Odersky";
42 private static final String LEX_SPOON = "Lex Spoon";
43
44 private static final String BILL_VENNERS = "Bill Venners";
45 private static final String JCIP = "Java Concurrency In Practice";
46 private static final double JCIP_PRICE = 37.79;
47 private static final Date JCIP_PUBLISHED = toDate("May 19, 2006");
48 private static final long JCIP_ISBN = 9780321349606L;
49 private static final boolean JCIP_READ = true;
50 private static final Integer JCIP_PAGES = 403;
51 private static final Supplier<String> JCIP_ABSTRACT = Suppliers.memoize(new BookAbstractSupplier("/com/atlassian/activeobjects/test/model/jcip.txt"));
52 private static final String JCIP_COVER = "/com/atlassian/activeobjects/test/model/jcip.jpg";
53
54 private static final String EJ2 = "Effective Java (Second Edition)";
55 private static final double EJ2_PRICE = 41.24;
56 private static final Date EJ2_PUBLISHED = toDate("May 28, 2008");
57 private static final long EJ2_ISBN = 9780321356680L;
58 private static final boolean EJ2_READ = false;
59 private static final Integer EJ2_PAGES = null;
60 private static final Supplier<String> EJ2_ABSTRACT = Suppliers.memoize(new BookAbstractSupplier("/com/atlassian/activeobjects/test/model/ej2.txt"));
61 private static final String EJ2_COVER = "/com/atlassian/activeobjects/test/model/ej2.jpg";
62
63 private static final String PIS = "Programming in Scala";
64 private static final double PIS_PRICE = 31.17;
65 private static final Date PIS_PUBLISHED = toDate("Jan 4, 2011");
66 private static final long PIS_ISBN = 9780981531601L;
67 private static final boolean PIS_READ = true;
68 private static final Integer PIS_PAGES = null;
69 private static final Supplier<String> PIS_ABSTRACT = Suppliers.memoize(new BookAbstractSupplier("/com/atlassian/activeobjects/test/model/pis.txt"));
70 private static final String PIS_COVER = "/com/atlassian/activeobjects/test/model/pis.jpg";
71
72 private final Logger logger = LoggerFactory.getLogger(this.getClass());
73
74 private final ActiveObjects ao;
75
76 public Model(EntityManager entityManager) {
77 this.ao = new TestActiveObjects(checkNotNull(entityManager));
78 }
79
80 public Model(ActiveObjects ao) {
81 this.ao = checkNotNull(ao);
82 }
83
84 public void emptyDatabase() {
85 logger.debug("Emptying the database!");
86 ao.migrateDestructively();
87 }
88
89 public void migrateEntities() {
90 final Class<? extends RawEntity<?>>[] entities = new Class[]{Book.class, Author.class, Authorship.class};
91 logger.debug("Migrating entities ({}), this will create tables", Joiner.on(',').join(entities));
92 ao.migrate(entities);
93 }
94
95 public void createData() {
96 logger.info("Adding data to the database!");
97 resetDatabase();
98
99 final Author[] jcip = authors(BRIAN_GOETZ, TIM_PEIERLS, JOSHUA_BLOCH, JOSEPH_BOWBEER, DAVID_HOLMES, DOUG_LEA);
100 book(JCIP, JCIP_PRICE, JCIP_ISBN, JCIP_PUBLISHED, JCIP_READ, JCIP_PAGES, JCIP_ABSTRACT.get(), jcip);
101
102 final Author[] scala = authors(MARTIN_ODERSKY, LEX_SPOON, BILL_VENNERS);
103 book(PIS, PIS_PRICE, PIS_ISBN, PIS_PUBLISHED, PIS_READ, PIS_PAGES, PIS_ABSTRACT.get(), scala);
104
105 book(EJ2, EJ2_PRICE, EJ2_ISBN, EJ2_PUBLISHED, EJ2_READ, EJ2_PAGES, EJ2_ABSTRACT.get(), findAuthorWithName(toList(jcip), JOSHUA_BLOCH));
106 }
107
108 private Author[] authors(String... names) {
109 return transform(newArrayList(names), new Function<String, Author>() {
110 public Author apply(String name) {
111 return author(name);
112 }
113 }).toArray(new Author[names.length]);
114 }
115
116 private Author author(String name) {
117 final Class<Author> type = Author.class;
118
119 final Author author = ao.create(type);
120 author.setName(name);
121 author.save();
122 return author;
123 }
124
125 private Book book(String title, double price, long isbn, Date published, boolean read, Integer pages,
126 String bookAbstract, Author... authors) {
127 final Book book = ao.create(Book.class, ImmutableMap.<String, Object>of("ISBN", isbn));
128 book.setTitle(title);
129 book.setAbstract(bookAbstract);
130 book.setPrice(price);
131 book.setRead(read);
132 book.setNumberOfPages(pages);
133 book.setPublished(published);
134 book.save();
135
136 for (Author author : authors) {
137 authorship(book, author);
138 }
139
140 return book;
141 }
142
143 private void authorship(Book book, Author author) {
144
145 final Authorship authorship = ao.create(Authorship.class);
146 authorship.setBook(book);
147 authorship.setAuthor(author);
148 authorship.save();
149 }
150
151 private void resetDatabase() {
152 emptyDatabase();
153 migrateEntities();
154 }
155
156 public void checkAuthors() {
157 ImmutableList<Author> authors = allAuthors();
158 assertEquals(9, authors.size());
159
160 assertEquals(1, findAuthorWithName(authors, BRIAN_GOETZ).getBooks().length);
161 assertEquals(1, findAuthorWithName(authors, TIM_PEIERLS).getBooks().length);
162 assertEquals(2, findAuthorWithName(authors, JOSHUA_BLOCH).getBooks().length);
163 assertEquals(1, findAuthorWithName(authors, JOSEPH_BOWBEER).getBooks().length);
164 assertEquals(1, findAuthorWithName(authors, DOUG_LEA).getBooks().length);
165 assertEquals(1, findAuthorWithName(authors, DAVID_HOLMES).getBooks().length);
166 assertEquals(1, findAuthorWithName(authors, MARTIN_ODERSKY).getBooks().length);
167 assertEquals(1, findAuthorWithName(authors, LEX_SPOON).getBooks().length);
168 assertEquals(1, findAuthorWithName(authors, BILL_VENNERS).getBooks().length);
169
170 final String me = "Me";
171
172 author(me);
173
174 ao.flushAll();
175
176 authors = allAuthors();
177 assertEquals(10, authors.size());
178 assertEquals(0, findAuthorWithName(authors, me).getBooks().length);
179 }
180
181 private Author findAuthorWithName(Iterable<Author> authors, final String name) {
182 return Iterables.find(authors, new Predicate<Author>() {
183 @Override
184 public boolean apply(Author author) {
185 return name.equals(author.getName());
186 }
187 });
188 }
189
190 private ImmutableList<Author> allAuthors() {
191 return toList(ao.find(Author.class));
192 }
193
194 public void checkBooks() {
195 final ImmutableList<Book> books = allBooks();
196
197 assertEquals(3, books.size());
198
199 checkBook(findBookWithTitle(books, JCIP), JCIP_ABSTRACT.get(), JCIP_PRICE, JCIP_ISBN, JCIP_PUBLISHED, JCIP_READ, JCIP_PAGES, 6);
200 checkBook(findBookWithTitle(books, PIS), PIS_ABSTRACT.get(), PIS_PRICE, PIS_ISBN, PIS_PUBLISHED, PIS_READ, PIS_PAGES, 3);
201 checkBook(findBookWithTitle(books, EJ2), EJ2_ABSTRACT.get(), EJ2_PRICE, EJ2_ISBN, EJ2_PUBLISHED, EJ2_READ, EJ2_PAGES, 1);
202 }
203
204 private void checkBook(Book book, String bookAbstract, double price, long isbn, Date published, boolean read, Integer pages, int i) {
205 assertEquals(bookAbstract, book.getAbstract());
206 assertEquals(price, book.getPrice(), 0d);
207 assertEquals(published.getTime(), book.getPublished().getTime());
208 assertEquals(isbn, book.getIsbn());
209 assertEquals(read, book.isRead());
210 assertEquals(pages, book.getNumberOfPages());
211 assertEquals(i, book.getAuthors().length);
212 }
213
214 private Book findBookWithTitle(Iterable<Book> books, final String title) {
215 return Iterables.find(books, new Predicate<Book>() {
216 @Override
217 public boolean apply(Book book) {
218 return title.equals(book.getTitle());
219 }
220 });
221 }
222
223 private ImmutableList<Book> allBooks() {
224 return toList(ao.find(Book.class));
225 }
226
227 private <T> ImmutableList<T> toList(T[] authors) {
228 return ImmutableList.copyOf(newArrayList(authors));
229 }
230
231 private static final class BookAbstractSupplier implements Supplier<String> {
232 private final String resource;
233
234 public BookAbstractSupplier(String resource) {
235 this.resource = resource;
236 }
237
238 @Override
239 public String get() {
240 return resource == null ? "" : load();
241 }
242
243 private String load() {
244 InputStream is = null;
245 try {
246 is = this.getClass().getResourceAsStream(resource);
247 return IOUtils.toString(is, "UTF-8");
248 } catch (IOException e) {
249 throw new IllegalStateException(e);
250 } finally {
251 IOUtils.closeQuietly(is);
252 }
253 }
254 }
255
256 private static Date toDate(String date) {
257 try {
258 final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT, Locale.US);
259 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
260 return sdf.parse(date);
261 } catch (ParseException e) {
262 throw new RuntimeException(e);
263 }
264 }
265 }