001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.examples.rest.petstore; 014 015import static java.text.MessageFormat.*; 016 017import java.io.*; 018import java.util.*; 019 020import javax.persistence.*; 021 022import org.apache.juneau.examples.rest.petstore.dto.*; 023import org.apache.juneau.examples.rest.petstore.rest.*; 024import org.apache.juneau.json.*; 025import org.apache.juneau.parser.ParseException; 026import org.apache.juneau.rest.client.*; 027import org.apache.juneau.utils.*; 028 029/** 030 * Pet store database application. 031 * <p> 032 * Uses JPA persistence to store and retrieve PetStore DTOs. 033 * JPA beans are defined in <c>META-INF/persistence.xml</c>. 034 * 035 * <ul class='seealso'> 036 * <li class='extlink'>{@source} 037 * </ul> 038 */ 039public class PetStoreService extends AbstractPersistenceService { 040 041 //----------------------------------------------------------------------------------------------------------------- 042 // Initialization methods. 043 //----------------------------------------------------------------------------------------------------------------- 044 045 /** 046 * Initialize the petstore database using JPA. 047 * 048 * @param w Console output. 049 * @return This object (for method chaining). 050 * @throws ParseException Malformed input encountered. 051 * @throws IOException File could not be read from file system. 052 */ 053 public PetStoreService initDirect(PrintWriter w) throws ParseException, IOException { 054 055 EntityManager em = getEntityManager(); 056 EntityTransaction et = em.getTransaction(); 057 JsonParser parser = JsonParser.create().build(); 058 059 et.begin(); 060 061 for (Pet x : em.createQuery("select X from PetstorePet X", Pet.class).getResultList()) { 062 em.remove(x); 063 w.println(format("Deleted pet: id={0}", x.getId())); 064 } 065 for (Order x : em.createQuery("select X from PetstoreOrder X", Order.class).getResultList()) { 066 em.remove(x); 067 w.println(format("Deleted order: id={0}", x.getId())); 068 } 069 for (User x : em.createQuery("select X from PetstoreUser X", User.class).getResultList()) { 070 em.remove(x); 071 w.println(format("Deleted user: username={0}", x.getUsername())); 072 } 073 074 et.commit(); 075 et.begin(); 076 077 for (Pet x : parser.parse(getStream("init/Pets.json"), Pet[].class)) { 078 x = em.merge(x); 079 w.println(format("Created pet: id={0}, name={1}", x.getId(), x.getName())); 080 } 081 for (Order x : parser.parse(getStream("init/Orders.json"), Order[].class)) { 082 x = em.merge(x); 083 w.println(format("Created order: id={0}", x.getId())); 084 } 085 for (User x: parser.parse(getStream("init/Users.json"), User[].class)) { 086 x = em.merge(x); 087 w.println(format("Created user: username={0}", x.getUsername())); 088 } 089 090 et.commit(); 091 092 return this; 093 } 094 095 /** 096 * Initialize the petstore database by using a remote resource interface against our REST. 097 * 098 * @param w Console output. 099 * @return This object (for method chaining). 100 * @throws ParseException Malformed input encountered. 101 * @throws IOException Thrown by client stream. 102 */ 103 public PetStoreService initViaRest(PrintWriter w) throws ParseException, IOException { 104 JsonParser parser = JsonParser.create().ignoreUnknownBeanProperties().build(); 105 106 String port = System.getProperty("juneau.serverPort", "8000"); 107 108 try (RestClient rc = RestClient.create().json().rootUrl("http://localhost:" + port).build()) { 109 PetStore ps = rc.getRemoteResource(PetStore.class); 110 111 for (Pet x : ps.getPets()) { 112 ps.deletePet("apiKey", x.getId()); 113 w.println(format("Deleted pet: id={0}", x.getId())); 114 } 115 for (Order x : ps.getOrders()) { 116 ps.deleteOrder(x.getId()); 117 w.println(format("Deleted order: id={0}", x.getId())); 118 } 119 for (User x : ps.getUsers()) { 120 ps.deleteUser(x.getUsername()); 121 w.println(format("Deleted user: username={0}", x.getUsername())); 122 } 123 for (CreatePet x : parser.parse(getStream("init/Pets.json"), CreatePet[].class)) { 124 long id = ps.postPet(x); 125 w.println(format("Created pet: id={0}, name={1}", id, x.getName())); 126 } 127 for (Order x : parser.parse(getStream("init/Orders.json"), Order[].class)) { 128 long id = ps.placeOrder(x.getPetId(), x.getUsername()); 129 w.println(format("Created order: id={0}", id)); 130 } 131 for (User x: parser.parse(getStream("init/Users.json"), User[].class)) { 132 ps.postUser(x); 133 w.println(format("Created user: username={0}", x.getUsername())); 134 } 135 } 136 137 return this; 138 } 139 140 //----------------------------------------------------------------------------------------------------------------- 141 // Service methods. 142 //----------------------------------------------------------------------------------------------------------------- 143 144 /** 145 * Returns the pet with the specified ID. 146 * 147 * @param id The pet ID. 148 * @return The pet with the specified ID. Never <jk>null</jk>. 149 * @throws IdNotFound If pet was not found. 150 */ 151 public Pet getPet(long id) throws IdNotFound { 152 return find(Pet.class, id); 153 } 154 155 /** 156 * Returns the order with the specified ID. 157 * 158 * @param id The order ID. 159 * @return The order with the specified ID. Never <jk>null</jk>. 160 * @throws IdNotFound If order was not found. 161 */ 162 public Order getOrder(long id) throws IdNotFound { 163 return find(Order.class, id); 164 } 165 166 /** 167 * Returns the user with the specified username. 168 * 169 * @param username The username. 170 * @return The user with the specified username. Never <jk>null</jk>. 171 * @throws InvalidUsername Username was not valid. 172 * @throws IdNotFound If order was not found. 173 */ 174 public User getUser(String username) throws InvalidUsername, IdNotFound { 175 assertValidUsername(username); 176 return find(User.class, username); 177 } 178 179 /** 180 * Returns all pets in the database. 181 * 182 * @return All pets in the database. 183 */ 184 public List<Pet> getPets() { 185 return query("select X from PetstorePet X", Pet.class, (SearchArgs)null); 186 } 187 188 /** 189 * Returns all orders in the database. 190 * 191 * @return All orders in the database. 192 */ 193 public List<Order> getOrders() { 194 return query("select X from PetstoreOrder X", Order.class, (SearchArgs)null); 195 } 196 197 /** 198 * Returns all users in the database. 199 * 200 * @return All users in the database. 201 */ 202 public List<User> getUsers() { 203 return query("select X from PetstoreUser X", User.class, (SearchArgs)null); 204 } 205 206 /** 207 * Creates a new pet in the database. 208 * 209 * @param c The pet input data. 210 * @return a new {@link Pet} object. 211 */ 212 public Pet create(CreatePet c) { 213 return merge(new Pet().status(PetStatus.AVAILABLE).apply(c)); 214 } 215 216 /** 217 * Creates a new order in the database. 218 * 219 * @param c The order input data. 220 * @return a new {@link Order} object. 221 */ 222 public Order create(CreateOrder c) { 223 return merge(new Order().status(OrderStatus.PLACED).apply(c)); 224 } 225 226 /** 227 * Creates a new user in the database. 228 * 229 * @param c The user input data. 230 * @return a new {@link User} object. 231 */ 232 public User create(User c) { 233 return merge(new User().apply(c)); 234 } 235 236 /** 237 * Updates a pet in the database. 238 * 239 * @param u The update information. 240 * @return The updated {@link Pet} object. 241 * @throws IdNotFound Pet was not found. 242 */ 243 public Pet update(UpdatePet u) throws IdNotFound { 244 EntityManager em = getEntityManager(); 245 return merge(em, find(em, Pet.class, u.getId()).apply(u)); 246 } 247 248 /** 249 * Updates an order in the database. 250 * 251 * @param o The update information. 252 * @return The updated {@link Order} object. 253 * @throws IdNotFound Order was not found. 254 */ 255 public Order update(Order o) throws IdNotFound { 256 EntityManager em = getEntityManager(); 257 return merge(em, find(em, Order.class, o.getId()).apply(o)); 258 } 259 260 /** 261 * Updates a user in the database. 262 * 263 * @param u The update information. 264 * @return The updated {@link User} object. 265 * @throws IdNotFound User was not found. 266 * @throws InvalidUsername The username was not valid. 267 */ 268 public User update(User u) throws IdNotFound, InvalidUsername { 269 assertValidUsername(u.getUsername()); 270 EntityManager em = getEntityManager(); 271 return merge(em, find(em, User.class, u.getUsername()).apply(u)); 272 } 273 274 /** 275 * Removes a pet from the database. 276 * 277 * @param id The pet ID. 278 * @throws IdNotFound Pet was not found. 279 */ 280 public void removePet(long id) throws IdNotFound { 281 EntityManager em = getEntityManager(); 282 remove(em, find(em, Pet.class, id)); 283 } 284 285 /** 286 * Removes an order from the database. 287 * 288 * @param id The order ID. 289 * @throws IdNotFound Order was not found. 290 */ 291 public void removeOrder(long id) throws IdNotFound { 292 EntityManager em = getEntityManager(); 293 remove(em, find(em, Order.class, id)); 294 } 295 296 /** 297 * Removes a user from the database. 298 * 299 * @param username The username. 300 * @throws IdNotFound User was not found. 301 */ 302 public void removeUser(String username) throws IdNotFound { 303 EntityManager em = getEntityManager(); 304 remove(em, find(em, User.class, username)); 305 } 306 307 /** 308 * Returns all pets with the specified statuses. 309 * 310 * @param status Pet statuses. 311 * @return Pets with the specified statuses. 312 */ 313 public Collection<Pet> getPetsByStatus(PetStatus[] status) { 314 return getEntityManager() 315 .createQuery("select X from PetstorePet X where X.status in :status", Pet.class) 316 .setParameter("status", status) 317 .getResultList(); 318 } 319 320 /** 321 * Returns all pets with the specified tags. 322 * 323 * @param tags Pet tags. 324 * @return Pets with the specified tags. 325 * @throws InvalidTag Tag name was invalid. 326 */ 327 public Collection<Pet> getPetsByTags(String[] tags) throws InvalidTag { 328 return getEntityManager() 329 .createQuery("select X from PetstorePet X where X.tags in :tags", Pet.class) 330 .setParameter("tags", tags) 331 .getResultList(); 332 } 333 334 /** 335 * Returns a summary of pet statuses and counts. 336 * 337 * @return A summary of pet statuses and counts. 338 */ 339 public Map<PetStatus,Integer> getInventory() { 340 Map<PetStatus,Integer> m = new LinkedHashMap<>(); 341 for (Pet p : getPets()) { 342 PetStatus ps = p.getStatus(); 343 if (! m.containsKey(ps)) 344 m.put(ps, 1); 345 else 346 m.put(ps, m.get(ps) + 1); 347 } 348 return m; 349 } 350 351 /** 352 * Returns <jk>true</jk> if the specified username and password is valid. 353 * 354 * @param username The username. 355 * @param password The password. 356 * @return <jk>true</jk> if the specified username and password is valid. 357 */ 358 public boolean isValid(String username, String password) { 359 return getUser(username).getPassword().equals(password); 360 } 361 362 //----------------------------------------------------------------------------------------------------------------- 363 // Helper methods 364 //----------------------------------------------------------------------------------------------------------------- 365 366 private void assertValidUsername(String username) throws InvalidUsername { 367 if (username == null || ! username.matches("[\\w\\d]{3,8}")) 368 throw new InvalidUsername(); 369 } 370 371 private InputStream getStream(String fileName) { 372 return getClass().getResourceAsStream(fileName); 373 } 374}