From 54689d2004a6a7cb7ec05b1191032d36241a6400 Mon Sep 17 00:00:00 2001 From: JamesBognar Date: Mon, 9 Sep 2019 18:08:40 -0400 Subject: [PATCH] Initial contents. --- .gitignore | 6 + juneau-petstore-api/.gitignore | 6 + juneau-petstore-api/src/assembly/bin.xml | 58 ++ .../org/apache/juneau/petstore/PetStore.java | 421 ++++++++++++++ .../juneau/petstore/dto/CreateOrder.java | 96 ++++ .../apache/juneau/petstore/dto/CreatePet.java | 139 +++++ .../juneau/petstore/dto/ExpiresAfter.java | 53 ++ .../juneau/petstore/dto/IdConflict.java | 38 ++ .../juneau/petstore/dto/IdNotFound.java | 38 ++ .../apache/juneau/petstore/dto/InvalidId.java | 35 ++ .../juneau/petstore/dto/InvalidLogin.java | 35 ++ .../juneau/petstore/dto/InvalidSpecies.java | 35 ++ .../juneau/petstore/dto/InvalidTag.java | 35 ++ .../juneau/petstore/dto/InvalidUsername.java | 35 ++ .../org/apache/juneau/petstore/dto/Order.java | 194 +++++++ .../juneau/petstore/dto/OrderStatus.java | 45 ++ .../org/apache/juneau/petstore/dto/Pet.java | 261 +++++++++ .../apache/juneau/petstore/dto/PetStatus.java | 45 ++ .../apache/juneau/petstore/dto/PetTag.java | 87 +++ .../juneau/petstore/dto/PetTagNameSwap.java | 43 ++ .../apache/juneau/petstore/dto/Species.java | 24 + .../apache/juneau/petstore/dto/UpdatePet.java | 122 ++++ .../org/apache/juneau/petstore/dto/User.java | 213 +++++++ .../juneau/petstore/dto/UserStatus.java | 44 ++ .../juneau/petstore/dto/package-info.java | 18 + .../apache/juneau/petstore/package-info.java | 18 + juneau-petstore-client/.gitignore | 6 + juneau-petstore-client/src/assembly/bin.xml | 58 ++ .../java/org/apache/juneau/petstore/Main.java | 112 ++++ .../apache/juneau/petstore/init/Orders.json | 18 + .../org/apache/juneau/petstore/init/Pets.json | 24 + .../apache/juneau/petstore/init/Users.json | 18 + juneau-petstore-server/.gitignore | 6 + .../juneau-examples-petstore-server.launch | 15 + juneau-petstore-server/src/assembly/bin.xml | 58 ++ .../java/org/apache/juneau/petstore/App.java | 34 ++ .../juneau/petstore/AppConfiguration.java | 62 ++ .../petstore/rest/PetStoreResource.java | 541 ++++++++++++++++++ .../juneau/petstore/rest/RootResources.java | 66 +++ .../service/AbstractPersistenceService.java | 273 +++++++++ .../petstore/service/PetStoreService.java | 329 +++++++++++ .../main/resources/META-INF/persistence.xml | 34 ++ .../src/main/resources/application.properties | 15 + .../src/main/resources/htdocs/background.jpg | Bin 0 -> 105889 bytes .../src/main/resources/htdocs/cat.png | Bin 0 -> 1878 bytes .../src/main/resources/juneau.cfg | 70 +++ .../src/main/resources/log4j.xml | 31 + 47 files changed, 3914 insertions(+) create mode 100644 .gitignore create mode 100644 juneau-petstore-api/.gitignore create mode 100644 juneau-petstore-api/src/assembly/bin.xml create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java create mode 100644 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java create mode 100755 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java create mode 100755 juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java create mode 100644 juneau-petstore-client/.gitignore create mode 100644 juneau-petstore-client/src/assembly/bin.xml create mode 100644 juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java create mode 100644 juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json create mode 100644 juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json create mode 100644 juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json create mode 100644 juneau-petstore-server/.gitignore create mode 100644 juneau-petstore-server/juneau-examples-petstore-server.launch create mode 100644 juneau-petstore-server/src/assembly/bin.xml create mode 100644 juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java create mode 100644 juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java create mode 100644 juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java create mode 100644 juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java create mode 100644 juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java create mode 100644 juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java create mode 100644 juneau-petstore-server/src/main/resources/META-INF/persistence.xml create mode 100644 juneau-petstore-server/src/main/resources/application.properties create mode 100644 juneau-petstore-server/src/main/resources/htdocs/background.jpg create mode 100644 juneau-petstore-server/src/main/resources/htdocs/cat.png create mode 100755 juneau-petstore-server/src/main/resources/juneau.cfg create mode 100644 juneau-petstore-server/src/main/resources/log4j.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34acf88 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/target/ +**/.DS_Store +.classpath +.project +/.settings/ +/bin/ diff --git a/juneau-petstore-api/.gitignore b/juneau-petstore-api/.gitignore new file mode 100644 index 0000000..34acf88 --- /dev/null +++ b/juneau-petstore-api/.gitignore @@ -0,0 +1,6 @@ +/target/ +**/.DS_Store +.classpath +.project +/.settings/ +/bin/ diff --git a/juneau-petstore-api/src/assembly/bin.xml b/juneau-petstore-api/src/assembly/bin.xml new file mode 100644 index 0000000..17e8ca8 --- /dev/null +++ b/juneau-petstore-api/src/assembly/bin.xml @@ -0,0 +1,58 @@ + + + + + + bin + + zip + + / + true + + + ${basedir}/../juneau-examples-petstore-api + / + + src/main/** + + + + ${basedir} + / + + src/main/** + files/** + .settings/** + .project + *.launch + *.cfg + + + + ${basedir}/build-overlay + / + true + + + + \ No newline at end of file diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java new file mode 100644 index 0000000..8bdfd47 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/PetStore.java @@ -0,0 +1,421 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore; + +import static org.apache.juneau.http.HttpMethodName.*; + +import java.util.*; + +import org.apache.juneau.jsonschema.annotation.Items; +import org.apache.juneau.petstore.dto.*; +import org.apache.juneau.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.remote.*; +import org.apache.juneau.http.exception.*; +import org.apache.juneau.http.response.*; + +/** + * Defines the interface for both the server-side and client-side pet store application. + * + *

+ * On the server side, this interface is implemented by the PetStoreResource class. + * + *

+ * On the client side, this interface is instantiated as a proxy using the RestClient.getRemoteProxy() method. + * + *

+ */ +@RemoteResource(path="/petstore") +public interface PetStore { + + //------------------------------------------------------------------------------------------------------------------ + // Pets + //------------------------------------------------------------------------------------------------------------------ + + /** + * Returns all pets in the database. + * + * @return All pets in the database. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/pet") + public Collection getPets() throws NotAcceptable; + + /** + * Returns a pet from the database. + * + * @param petId The ID of the pet to retrieve. + * @return The pet. + * @throws IdNotFound Pet was not found. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(path="/pet/{petId}") /* method inferred from method name */ + public Pet getPet( + @Path( + name="petId", + description="ID of pet to return", + example="123" + ) + long petId + ) throws IdNotFound, NotAcceptable; + + /** + * Adds a pet to the database. + * + * @param pet The pet data to add to the database. + * @return {@link Ok} if successful. + * @throws IdConflict ID already in use. + * @throws NotAcceptable Unsupported Accept header specified. + * @throws UnsupportedMediaType Unsupported Content-Type header specified. + */ + @RemoteMethod(method=POST, path="/pet") + public long createPet( + @Body( + description="Pet object to add to the store" + ) CreatePet pet + ) throws IdConflict, NotAcceptable, UnsupportedMediaType; + + /** + * Updates a pet in the database. + * + * @param pet The pet data to add to the database. + * @return {@link Ok} if successful. + * @throws IdNotFound ID not found. + * @throws NotAcceptable Unsupported Accept header specified. + * @throws UnsupportedMediaType Unsupported Content-Type header specified. + */ + @RemoteMethod(method=PUT, path="/pet/{petId}") + public Ok updatePet( + @Body( + description="Pet object that needs to be added to the store" + ) UpdatePet pet + ) throws IdNotFound, NotAcceptable, UnsupportedMediaType; + + /** + * Find all pets with the matching statuses. + * + * @param status The statuses to match against. + * @return The pets that match the specified statuses. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/pet/findByStatus") + public Collection findPetsByStatus( + @Query( + name="status", + description="Status values that need to be considered for filter.", + required=true, + type="array", + collectionFormat="csv", + items=@Items( + type="string", + _enum="AVAILABLE,PENDING,SOLD", + _default="AVAILABLE" + ), + example="AVALIABLE,PENDING" + ) + PetStatus[] status + ) throws NotAcceptable; + + /** + * Find all pets with the specified tags. + * + * @param tags The tags to match against. + * @return The pets that match the specified tags. + * @throws InvalidTag Invalid tag was specified. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/pet/findByTags") + @Deprecated + public Collection findPetsByTags( + @Query( + name="tags", + description="Tags to filter by", + required=true, + example="['tag1','tag2']" + ) + String[] tags + ) throws InvalidTag, NotAcceptable; + + /** + * Deletes the specified pet. + * + * @param apiKey Security key. + * @param petId ID of pet to delete. + * @return {@link Ok} if successful. + * @throws IdNotFound Pet not found. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=DELETE, path="/pet/{petId}") + public Ok deletePet( + @Header( + name="api_key", + description="Security API key", + required=true, + example="foobar" + ) + String apiKey, + @Path( + name="petId", + description="Pet id to delete", + example="123" + ) + long petId + ) throws IdNotFound, NotAcceptable; + + //------------------------------------------------------------------------------------------------------------------ + // Orders + //------------------------------------------------------------------------------------------------------------------ + + /** + * Returns all orders in the database. + * + * @return All orders in the database. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/store/order") + public Collection getOrders() throws NotAcceptable; + + /** + * Returns an order from the database. + * + * @param orderId The ID of the order to retreieve. + * @return The retrieved order. + * @throws InvalidId ID was invalid. + * @throws IdNotFound Order was not found. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/store/order/{orderId}") + public Order getOrder( + @Path( + name="orderId", + description="ID of order to fetch", + maximum="1000", + minimum="1", + example="123" + ) + long orderId + ) throws InvalidId, IdNotFound, NotAcceptable; + + /** + * Adds an order to the database. + * + * @param petId Id of pet to order. + * @param username The username of the user placing the order. + * @return The ID of the order. + * @throws IdConflict ID was already in use. + * @throws NotAcceptable Unsupported Accept header specified. + * @throws UnsupportedMediaType Unsupported Content-Type header specified. + */ + @RemoteMethod(method=POST, path="/store/order") + public long placeOrder( + @FormData( + name="petId", + description="Pet ID" + ) + long petId, + @FormData( + name="username", + description="The username of the user creating the order" + ) + String username + ) throws IdConflict, NotAcceptable, UnsupportedMediaType; + + /** + * Deletes an order from the database. + * + * @param orderId The order ID. + * @return {@link Ok} if successful. + * @throws InvalidId ID not valid. + * @throws IdNotFound Order not found. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=DELETE, path="/store/order/{orderId}") + public Ok deleteOrder( + @Path( + name="orderId", + description="ID of the order that needs to be deleted", + minimum="1", + example="5" + ) + long orderId + ) throws InvalidId, IdNotFound, NotAcceptable; + + /** + * Returns an inventory of pet statuses and counts. + * + * @return An inventory of pet statuses and counts. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/store/inventory") + public Map getStoreInventory() throws NotAcceptable; + + //------------------------------------------------------------------------------------------------------------------ + // Users + //------------------------------------------------------------------------------------------------------------------ + + /** + * Returns all users in the database. + * + * @return All users in the database. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/user") + public Collection getUsers() throws NotAcceptable; + + /** + * Returns a user from the database. + * + * @param username The username. + * @return The user. + * @throws InvalidUsername Invalid username. + * @throws IdNotFound username not found. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/user/{username}") + public User getUser( + @Path( + name="username", + description="The name that needs to be fetched. Use user1 for testing." + ) + String username + ) throws InvalidUsername, IdNotFound, NotAcceptable; + + /** + * Adds a new user to the database. + * + * @param user The user to add to the database. + * @return {@link Ok} if successful. + * @throws InvalidUsername Username was invalid. + * @throws IdConflict Username already in use. + * @throws NotAcceptable Unsupported Accept header specified. + * @throws UnsupportedMediaType Unsupported Content-Type header specified. + */ + @RemoteMethod(method=POST, path="/user") + public Ok createUser( + @Body( + description="Created user object" + ) + User user + ) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType; + + /** + * Bulk creates users. + * + * @param users The users to add to the database. + * @return {@link Ok} if successful. + * @throws InvalidUsername Username was invalid. + * @throws IdConflict Username already in use. + * @throws NotAcceptable Unsupported Accept header specified. + * @throws UnsupportedMediaType Unsupported Content-Type header specified. + */ + @RemoteMethod(method=POST, path="/user/createWithArray") + public Ok createUsers( + @Body( + description="List of user objects" + ) + User[] users + ) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType; + + /** + * Updates a user in the database. + * + * @param username The username. + * @param user The updated information. + * @return {@link Ok} if successful. + * @throws InvalidUsername Username was invalid. + * @throws IdNotFound User was not found. + * @throws NotAcceptable Unsupported Accept header specified. + * @throws UnsupportedMediaType Unsupported Content-Type header specified. + */ + @RemoteMethod(method=PUT, path="/user/{username}") + public Ok updateUser( + @Path( + name="username", + description="Name that need to be updated" + ) + String username, + @Body( + description="Updated user object" + ) + User user + ) throws InvalidUsername, IdNotFound, NotAcceptable, UnsupportedMediaType; + + /** + * Deletes a user from the database. + * + * @param username The username. + * @return {@link Ok} if successful. + * @throws InvalidUsername Username was not valid. + * @throws IdNotFound User was not found. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=DELETE, path="/user/{username}") + public Ok deleteUser( + @Path( + name="username", + description="The name that needs to be deleted" + ) + String username + ) throws InvalidUsername, IdNotFound, NotAcceptable; + + /** + * User login. + * + * @param username The username for login. + * @param password The password for login in clear text. + * @param rateLimit Calls per hour allowed by the user. + * @param expiresAfter The Expires-After response header. + * @param req The servlet request. + * @param res The servlet response. + * @return {@link Ok} if successful. + * @throws InvalidLogin Login was unsuccessful. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/user/login") + public Ok login( + @Query( + name="username", + description="The username for login.", + required=true, + example="myuser" + ) + String username, + @Query( + name="password", + description="The password for login in clear text.", + required=true, + example="abc123" + ) + String password, + @ResponseHeader( + name="X-Rate-Limit", + type="integer", + format="int32", + description="Calls per hour allowed by the user.", + example="123" + ) + Value rateLimit, + Value expiresAfter + ) throws InvalidLogin, NotAcceptable; + + /** + * User logout. + * + * @return {@link Ok} if successful. + * @throws NotAcceptable Unsupported Accept header specified. + */ + @RemoteMethod(method=GET, path="/user/logout") + public Ok logout() throws NotAcceptable; +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java new file mode 100644 index 0000000..db9686e --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreateOrder.java @@ -0,0 +1,96 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.annotation.*; + +/** + * Bean for creating {@link Order} objects. + * + *
    + *
+ */ +@Bean(fluentSetters=true, properties="petId,username") +public class CreateOrder { + + private long petId; + private String username; + + /** + * Optional constructor. + * + * @param petId The petId property value. + * @param username The username property value. + */ + @BeanConstructor(properties="petId,username") + public CreateOrder(long petId, String username) { + this.petId = petId; + this.username = username; + } + + /** + * Constructor needed by JPA. + */ + public CreateOrder() {} + + //----------------------------------------------------------------------------------------------------------------- + // Bean properties + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return The petId property value. + */ + public long getPetId() { + return petId; + } + + /** + * @param value The petId property value. + * @return This object (for method chaining). + */ + public CreateOrder petId(long value) { + this.petId = value; + return this; + } + + /** + * @return The username property value. + */ + public String getUsername() { + return username; + } + + /** + * @param value The username property value. + * @return This object (for method chaining). + */ + public CreateOrder username(String value) { + this.username = value; + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Other + //----------------------------------------------------------------------------------------------------------------- + + /** + * Used to populate Swagger examples. + * Example is inferred from the method name. + * + * @return An example POJO. + */ + public static CreateOrder example() { + return new CreateOrder(123, "sampleuser"); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java new file mode 100644 index 0000000..2064cc2 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/CreatePet.java @@ -0,0 +1,139 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.jsonschema.annotation.*; + +/** + * Bean for creating {@link Pet} objects. + * + *
    + *
+ */ +@Bean(fluentSetters=true, properties="name,price,species,tags") +public class CreatePet { + + @Schema(description="Pet name.", minLength=3, maxLength=50) + private String name; + + @Schema(description="Price of pet.", maximum="999.99") + private float price; + + @Schema(description="Pet species.") + private Species species; + + @Schema(description="Pet attributes.", example="friendly,smart") + private String[] tags; + + /** + * Constructor. + * + * @param name The name property value. + * @param price The price property value. + * @param species The species property value. + * @param tags The tags property value. + * @param photo The photo property value. + */ + public CreatePet(String name, float price, Species species, String[] tags) { + this.name = name; + this.price = price; + this.species = species; + this.tags = tags; + } + + /** + * Empty constructor. + */ + public CreatePet() {} + + //----------------------------------------------------------------------------------------------------------------- + // Bean properties + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return The name property value. + */ + public String getName() { + return name; + } + + /** + * @param value The name property value. + * @return This object (for method chaining). + */ + public CreatePet name(String value) { + this.name = value; + return this; + } + + /** + * @return The price property value. + */ + public float getPrice() { + return price; + } + + /** + * @param value The price property value. + * @return This object (for method chaining). + */ + public CreatePet price(float value) { + this.price = value; + return this; + } + + /** + * @return The species property value. + */ + public Species getSpecies() { + return species; + } + + /** + * @param value The species property value. + * @return This object (for method chaining). + */ + public CreatePet species(Species value) { + this.species = value; + return this; + } + + /** + * @return The tags property value. + */ + public String[] getTags() { + return tags; + } + + /** + * @param value The tags property value. + * @return This object (for method chaining). + */ + public CreatePet tags(String...value) { + this.tags = value; + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Other + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return An example POJO. + */ + public static CreatePet example() { + return new CreatePet("Doggie", 9.99f, Species.DOG, new String[]{"smart","friendly"}); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java new file mode 100644 index 0000000..8273edf --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/ExpiresAfter.java @@ -0,0 +1,53 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import java.util.*; + +import org.apache.juneau.http.annotation.*; + +/** + * X-Expires-After custom HTTP header. + * + *
    + *
+ */ +@ResponseHeader( + name="X-Expires-After", + type="string", + format="date-time", + description="Date in UTC when token expires", + example="2012-10-21" +) +public class ExpiresAfter { + private final Calendar c; + + /** + * Constructor. + * + * @param d The header value. + */ + public ExpiresAfter(Date d) { + this.c = new GregorianCalendar(); + c.setTime(d); + } + + /** + * The header value. + * @return The header value. + */ + public Calendar toCalendar() { + return c; + } +} \ No newline at end of file diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java new file mode 100644 index 0000000..5a22a1d --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdConflict.java @@ -0,0 +1,38 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when trying to add an entry where the ID is already in use. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="ID already in use") +public class IdConflict extends Conflict { + + /** + * Constructor. + * + * @param id The duplicate ID. + * @param c The object type.. + */ + public IdConflict(Object id, Class c) { + super("ID ''{0}'' already in use for type ''{1}''", id, c.getSimpleName()); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java new file mode 100644 index 0000000..b086f8e --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/IdNotFound.java @@ -0,0 +1,38 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when trying to add an entry where the ID is already in use. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="ID not found") +public class IdNotFound extends NotFound { + + /** + * Constructor. + * + * @param id The duplicate ID. + * @param c The object type.. + */ + public IdNotFound(Object id, Class c) { + super("ID ''{0}'' not found for type ''{1}''", id, c.getSimpleName()); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java new file mode 100644 index 0000000..d7ee807 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidId.java @@ -0,0 +1,35 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when trying to add an entry where the ID is already in use. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="Invalid ID provided") +public class InvalidId extends BadRequest { + + /** + * Constructor. + */ + public InvalidId() { + super("Invalid ID provided."); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java new file mode 100644 index 0000000..25f6bd9 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidLogin.java @@ -0,0 +1,35 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when an invalid username or password is provided. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="Invalid username or password provided") +public class InvalidLogin extends Unauthorized { + + /** + * Constructor. + */ + public InvalidLogin() { + super("Invalid username or password."); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java new file mode 100644 index 0000000..19cef69 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidSpecies.java @@ -0,0 +1,35 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when an invalid species is looked up. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="Invalid species provided") +public class InvalidSpecies extends BadRequest { + + /** + * Constructor. + */ + public InvalidSpecies() { + super("Invalid species provided."); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java new file mode 100644 index 0000000..4e2199e --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidTag.java @@ -0,0 +1,35 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when trying to add an entry where the ID is already in use. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="Invalid tag provided") +public class InvalidTag extends BadRequest { + + /** + * Constructor. + */ + public InvalidTag() { + super("Invalid tag provided. Must be at most 8 characters or digits."); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java new file mode 100644 index 0000000..46644a3 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/InvalidUsername.java @@ -0,0 +1,35 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.http.exception.*; + +/** + * Exception thrown when trying to add an entry where the ID is already in use. + * + *
    + *
+ */ +@SuppressWarnings("serial") +@Response(description="Invalid username provided") +public class InvalidUsername extends BadRequest { + + /** + * Constructor. + */ + public InvalidUsername() { + super("Invalid username provided. Must be between 3 and 8 characters or digits."); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java new file mode 100644 index 0000000..27fb0b3 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Order.java @@ -0,0 +1,194 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import static javax.persistence.TemporalType.*; + +import java.util.*; + +import javax.persistence.*; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.jsonschema.annotation.*; +import org.apache.juneau.transforms.*; + +/** + * Order bean. + * + *
    + *
+ */ +@Bean(fluentSetters=true, properties="id,petId,username,status,shipDate") +@Example("{id:123,petId:456,shipDate:'2012-12-21',status:'APPROVED'}") +@Entity(name="PetstoreOrder") +public class Order { + + @Column @Id @GeneratedValue + @Schema(description="Unique identifier for this order.") + @Html(link="servlet:/store/order/{id}") + private long id; + + @Column + @Schema(description="Pet unique identifier.") + @Html(link="servlet:/pet/{id}") + private long petId; + + @Column(length=20) + @Schema(description="User who created this order.", minLength=3, maxLength=20) + @Html(link="servlet:/user/{username}") + private String username; + + @Column + @Enumerated(EnumType.STRING) + @Schema(description="The current order status.") + private OrderStatus status; + + @Column @Temporal(TIMESTAMP) + @Schema(description="The ship date for this order.", format="date-time") + @Swap(TemporalDateSwap.IsoLocalDate.class) + private Date shipDate; + + /** + * Applies the specified create data to this order. + * + * @param o The create data to apply. + * @return This object. + */ + public Order apply(CreateOrder o) { + this.petId = o.getPetId(); + this.username = o.getUsername(); + return this; + } + + /** + * Applies the specified order this order. + * + * @param o The order to apply. + * @return This object. + */ + public Order apply(Order o) { + this.id = o.getId(); + this.petId = o.getPetId(); + this.username = o.getUsername(); + this.status = o.getStatus(); + this.shipDate = o.getShipDate(); + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Bean properties + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return The id property value. + */ + public long getId() { + return id; + } + + /** + * @param value The id property value. + * @return This object (for method chaining). + */ + public Order id(long value) { + this.id = value; + return this; + } + + /** + * @return The shipDate property value. + */ + public Date getShipDate() { + return shipDate; + } + + /** + * @param value The shipDate property value. + * @return This object (for method chaining). + */ + public Order shipDate(Date value) { + this.shipDate = value; + return this; + } + + /** + * @return The status property value. + */ + public OrderStatus getStatus() { + return status; + } + + /** + * @param value The status property value. + * @return This object (for method chaining). + */ + public Order status(OrderStatus value) { + this.status = value; + return this; + } + + /** + * @return The petId property value. + */ + public long getPetId() { + return petId; + } + + /** + * @param value The petId property value. + * @return This object (for method chaining). + */ + public Order petId(long value) { + this.petId = value;; + return this; + } + + /** + * @return The username property value. + */ + public String getUsername() { + return username; + } + + /** + * @param value The username property value. + * @return This object (for method chaining). + */ + public Order username(String value) { + this.username = value; + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Other + //----------------------------------------------------------------------------------------------------------------- + + /** + * This shows an example generated from a static method. + * + * @return The example POJO. + */ + @Example + public static Order example() { + return new Order() + .id(123) + .username("sampleuser") + .petId(456) + .status(OrderStatus.APPROVED) + .shipDate(DateUtils.parseISO8601("2020-10-10")) + ; + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java new file mode 100644 index 0000000..0c5e01e --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/OrderStatus.java @@ -0,0 +1,45 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.html.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.serializer.*; + +/** + * Enum of all possible order statuses. + * + *
    + *
+ */ +@Html(render=OrderStatus.OrderStatusRender.class) +@SuppressWarnings("javadoc") +public enum OrderStatus { + PLACED, APPROVED, DELIVERED; + + /** + * Used to control how this enum is rendered in HTML view. + */ + public static class OrderStatusRender extends HtmlRender { + @Override /* HtmlRender */ + public String getStyle(SerializerSession session, OrderStatus value) { + switch(value) { + case PLACED: return "background-color:#5cb85c;text-align:center;vertical-align:middle;"; + case APPROVED: return "background-color:#f0ad4e;text-align:center;vertical-align:middle;"; + case DELIVERED: return "background-color:#777;text-align:center;vertical-align:middle;"; + default: return "background-color:#888;text-align:center;vertical-align:middle;"; + } + } + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java new file mode 100644 index 0000000..cb9dff0 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Pet.java @@ -0,0 +1,261 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import static javax.persistence.EnumType.*; + +import java.util.*; + +import javax.persistence.*; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.html.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.jsonschema.annotation.*; +import org.apache.juneau.serializer.*; + +/** + * Pet bean. + * + *
    + *
+ */ +@Bean(typeName="Pet", fluentSetters=true, properties="id,species,name,tags,price,status") +@Entity(name="PetstorePet") +public class Pet { + + @Column @Id @GeneratedValue + @Schema(description="Unique identifier for this pet.") + @Html(link="servlet:/pet/{id}") + private long id; + + @Column(length=50) + @Schema(description="Pet name.", minLength=3, maxLength=50) + private String name; + + @Column + @Schema(description="Price of pet.", maximum="999.99") + @Html(render=PriceRender.class) + private float price; + + @Column + @Schema(description="Pet species.") + private Species species; + + @ElementCollection @OrderColumn + @Schema(description="Pet attributes.", example="friendly,smart") + private List tags; + + @Column @Enumerated(STRING) + @Schema(description="Pet species.") + private PetStatus status; + + /** + * Applies the specified data to this object. + * + * @param x The data to apply. + * @return This object. + */ + public Pet apply(CreatePet x) { + this.name = x.getName(); + this.price = x.getPrice(); + this.species = x.getSpecies(); + this.tags = x.getTags() == null ? null : Arrays.asList(x.getTags()); + return this; + } + + /** + * Applies the specified data to this object. + * + * @param x The data to apply. + * @return This object. + */ + public Pet apply(UpdatePet x) { + this.id = x.getId(); + this.name = x.getName(); + this.price = x.getPrice(); + this.species = x.getSpecies(); + this.tags = Arrays.asList(x.getTags()); + this.status = x.getStatus(); + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Bean properties + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return The id property value. + */ + public long getId() { + return id; + } + + /** + * @param value The id property value. + * @return This object (for method chaining). + */ + public Pet id(long value) { + this.id = value; + return this; + } + + /** + * @return The name property value. + */ + public String getName() { + return name; + } + + /** + * @param value The name property value. + * @return This object (for method chaining). + */ + public Pet name(String value) { + this.name = value; + return this; + } + + /** + * @return The price property value. + */ + public float getPrice() { + return price; + } + + /** + * @param value The price property value. + * @return This object (for method chaining). + */ + public Pet price(float value) { + this.price = value; + return this; + } + + /** + * @return The species property value. + */ + public Species getSpecies() { + return species; + } + + /** + * @param value The species property value. + * @return This object (for method chaining). + */ + public Pet species(Species value) { + this.species = value; + return this; + } + + /** + * @return The tags property value. + */ + public List getTags() { + return tags; + } + + /** + * @param value The tags property value. + * @return This object (for method chaining). + */ + public Pet tags(List value) { + this.tags = value; + return this; + } + + /** + * @param value The tags property value. + * @return This object (for method chaining). + */ + public Pet tags(String...value) { + this.tags = Arrays.asList(value); + return this; + } + + /** + * @return The status property value. + */ + public PetStatus getStatus() { + return status; + } + + /** + * @param value The status property value. + * @return This object (for method chaining). + */ + public Pet status(PetStatus value) { + this.status = value; + return this; + } + + /** + * @param statuses The statuses to match against. + * @return true if this pet matches at least one of the specified statuses. + */ + public boolean hasStatus(PetStatus...statuses) { + for (PetStatus status : statuses) + if (this.status == status) + return true; + return false; + } + + /** + * @param tags The tags to match against. + * @return true if this pet matches at least one of the specified tags. + */ + public boolean hasTag(String...tags) { + for (String tag : tags) + for (String t : this.tags) + if (t.equals(tag)) + return true; + return false; + } + + /** + * @return Edit page link. + */ + public java.net.URI getEdit() { + return java.net.URI.create("servlet:/pet/edit/{id}"); + } + + //----------------------------------------------------------------------------------------------------------------- + // Other + //----------------------------------------------------------------------------------------------------------------- + + /** + * This shows an example generated from a static method. + * + * @return POJO example. + */ + @Example + public static Pet example() { + return new Pet() + .id(123) + .species(Species.DOG) + .name("Doggie") + .tags("friendly","smart") + .status(PetStatus.AVAILABLE); + } + + /** + * Used to control format of prices in HTML view. + */ + public static final class PriceRender extends HtmlRender { + @Override + public Object getContent(SerializerSession session, Float value) { + return value == null ? null : String.format("$%.2f", value); + } + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java new file mode 100644 index 0000000..42abc3a --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetStatus.java @@ -0,0 +1,45 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.html.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.serializer.*; + +/** + * Enum of all possible pet statuses. + * + *
    + *
+ */ +@Html(render=PetStatus.PetStatusRender.class) +@SuppressWarnings("javadoc") +public enum PetStatus { + AVAILABLE, PENDING, SOLD, UNKNOWN; + + /** + * Used to control how this enum is rendered in HTML view. + */ + public static class PetStatusRender extends HtmlRender { + @Override /* HtmlRender */ + public String getStyle(SerializerSession session, PetStatus value) { + switch(value) { + case AVAILABLE: return "background-color:#5cb85c;text-align:center;vertical-align:middle;"; + case PENDING: return "background-color:#f0ad4e;text-align:center;vertical-align:middle;"; + case SOLD: return "background-color:#888;text-align:center;vertical-align:middle;"; + default: return "background-color:#777;text-align:center;vertical-align:middle;"; + } + } + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java new file mode 100644 index 0000000..34577ab --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTag.java @@ -0,0 +1,87 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import java.util.*; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.internal.*; + +/** + * Pet tag bean. + * + *
    + *
+ */ +@Bean(typeName="Tag", fluentSetters=true) +@Swap(PetTagNameSwap.class) +public class PetTag { + private long id; + private String name; + + /** + * @return The id property value. + */ + public long getId() { + return id; + } + + /** + * @param value The id property value. + * @return This object (for method chaining). + */ + public PetTag id(long value) { + this.id = value; + return this; + } + + /** + * @return The name property value. + */ + public String getName() { + return name; + } + + /** + * @param value The name property value. + * @return This object (for method chaining). + */ + public PetTag name(String value) { + this.name = value; + return this; + } + + /** + * @return POJO example. + */ + @Example + public static PetTag example() { + return new PetTag() + .id(123) + .name("MyTag"); + } + + /** + * @param tags Tags to convert to a simple string. + * @return The specified tags as a simple comma-delimited list. + */ + public static String asString(List tags) { + if (tags == null) + return ""; + List l = new ArrayList<>(tags.size()); + for (PetTag t : tags) + l.add(t.getName()); + return StringUtils.join(l, ','); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java new file mode 100644 index 0000000..7e1442f --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/PetTagNameSwap.java @@ -0,0 +1,43 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.*; +import org.apache.juneau.http.*; +import org.apache.juneau.transform.*; + +/** + * Swap for {@link PetTag} beans. + * + *
    + *
+ */ +public class PetTagNameSwap extends PojoSwap { + + /** + * Swap PetTag with name. + */ + @Override + public String swap(BeanSession bs, PetTag o) throws Exception { + return o.getName(); + } + + /** + * This is only applicable to HTML serialization. + */ + @Override + public MediaType[] forMediaTypes() { + return new MediaType[] { MediaType.HTML }; + } +} \ No newline at end of file diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java new file mode 100644 index 0000000..90a54e3 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/Species.java @@ -0,0 +1,24 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +/** + * Enum of all possible animal types. + * + *
    + *
+ */ +public enum Species { + BIRD, CAT, DOG, FISH, MOUSE, RABBIT, SNAKE; +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java new file mode 100644 index 0000000..d4b671f --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UpdatePet.java @@ -0,0 +1,122 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.jsonschema.annotation.*; + +/** + * Bean for updating {@link Pet} objects. + * + *
    + *
+ */ +@Bean(fluentSetters=true, properties="id,name,price,species,tags,status") +public class UpdatePet extends CreatePet { + + @Schema(description="Pet identifier.", minimum="1") + private long id; + + @Schema(description="Updated pet status.") + private PetStatus status; + + /** + * Constructor. + * + * @param id The id property value. + * @param name The name property value. + * @param price The price property value. + * @param species The species property value. + * @param tags The tags property value. + * @param status The status property value. + */ + public UpdatePet(long id, String name, float price, Species species, String[] tags, PetStatus status) { + super(name, price, species, tags); + this.id = id; + this.status = status; + } + + /** + * Empty constructor. + */ + public UpdatePet() {} + + //----------------------------------------------------------------------------------------------------------------- + // Bean properties + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return The id property value. + */ + public long getId() { + return id; + } + + /** + * @param value The id property value. + * @return This object (for method chaining). + */ + public UpdatePet id(long value) { + this.id = value; + return this; + } + + /** + * @return The status property value. + */ + public PetStatus getStatus() { + return status; + } + + /** + * @param value The status property value. + * @return This object (for method chaining). + */ + public UpdatePet status(PetStatus value) { + this.status = value; + return this; + } + + @Override + public UpdatePet name(String value) { + super.name(value); + return this; + } + + @Override + public UpdatePet price(float value) { + super.price(value); + return this; + } + + @Override + public UpdatePet species(Species value) { + super.species(value); + return this; + } + + @Override + public UpdatePet tags(String...value) { + super.tags(value); + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Other + //----------------------------------------------------------------------------------------------------------------- + + public static UpdatePet example() { + return new UpdatePet(123, "Doggie", 9.99f, Species.DOG, new String[]{"smart","friendly"}, PetStatus.SOLD); + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java new file mode 100644 index 0000000..eefa4c5 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/User.java @@ -0,0 +1,213 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import static javax.persistence.EnumType.*; + +import javax.persistence.*; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.jsonschema.annotation.*; + +/** + * User bean. + * + *
    + *
+ */ +@Bean(typeName="User", fluentSetters=true, properties="username,firstName,lastName,email,password,phone,userStatus") +@Entity(name="PetstoreUser") +public class User { + + @Id + @Column(length=8) + @Schema(description="Username.", minLength=3, maxLength=8) + @Html(link="servlet:/user/{username}") + private String username; + + @Column(length=50) + @Schema(description="First name.", maxLength=50) + private String firstName; + + @Column(length=50) + @Schema(description="First name.", maxLength=50) + private String lastName; + + @Column(length=50) + @Schema(description="First name.", maxLength=50, pattern="\\S+\\@\\S+") + private String email; + + @Column(length=8) + @Schema(description="Password.", minLength=3, maxLength=8, pattern="[\\w\\d]{3,8}") + private String password; + + @Column + @Schema(description="Phone number.", minLength=12, maxLength=12, pattern="\\d{3}\\-\\d{3}\\-\\d{4}") + private String phone; + + @Column + @Enumerated(STRING) + private UserStatus userStatus; + + /** + * Applies the specified data to this object. + * + * @param c The data to apply. + * @return This object. + */ + public User apply(User c) { + this.username = c.getUsername(); + this.firstName = c.getFirstName(); + this.lastName = c.getLastName(); + this.email = c.getEmail(); + this.password = c.getPassword(); + this.phone = c.getPhone(); + this.userStatus = c.getUserStatus(); + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Bean properties + //----------------------------------------------------------------------------------------------------------------- + + /** + * @return The username property value. + */ + public String getUsername() { + return username; + } + + /** + * @param value The username property value. + * @return This object (for method chaining). + */ + public User username(String value) { + this.username = value; + return this; + } + + /** + * @return The firstName property value. + */ + public String getFirstName() { + return firstName; + } + + /** + * @param value The firstName property value. + * @return This object (for method chaining). + */ + public User firstName(String value) { + this.firstName = value; + return this; + } + + /** + * @return The lastName property value. + */ + public String getLastName() { + return lastName; + } + + /** + * @param value The lastName property value. + * @return This object (for method chaining). + */ + public User lastName(String value) { + this.lastName = value; + return this; + } + + /** + * @return The email property value. + */ + public String getEmail() { + return email; + } + + /** + * @param value The email property value. + * @return This object (for method chaining). + */ + public User email(String value) { + this.email = value; + return this; + } + + /** + * @return The password property value. + */ + public String getPassword() { + return password; + } + + /** + * @param value The password property value. + * @return This object (for method chaining). + */ + public User password(String value) { + this.password = value; + return this; + } + + /** + * @return The phone property value. + */ + public String getPhone() { + return phone; + } + + /** + * @param value The phone property value. + * @return This object (for method chaining). + */ + public User phone(String value) { + this.phone = value; + return this; + } + + /** + * @return The userStatus property value. + */ + public UserStatus getUserStatus() { + return userStatus; + } + + /** + * @param value The userStatus property value. + * @return This object (for method chaining). + */ + public User userStatus(UserStatus value) { + this.userStatus = value; + return this; + } + + //----------------------------------------------------------------------------------------------------------------- + // Other + //----------------------------------------------------------------------------------------------------------------- + + /** + * This shows an example generated from a static method. + */ + @Example + public static User EXAMPLE = new User() + .username("billy") + .firstName("Billy") + .lastName("Bob") + .email("billy@apache.org") + .userStatus(UserStatus.ACTIVE) + .phone("111-222-3333"); + +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java new file mode 100644 index 0000000..1049c45 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/UserStatus.java @@ -0,0 +1,44 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.dto; + +import org.apache.juneau.html.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.serializer.*; + +/** + * Enum of all possible user statuses. + * + *
    + *
+ */ +@Html(render=UserStatus.UserStatusRender.class) +@SuppressWarnings("javadoc") +public enum UserStatus { + ACTIVE, INACTIVE; + + /** + * Used to control how this enum is rendered in HTML view. + */ + public static class UserStatusRender extends HtmlRender { + @Override /* HtmlRender */ + public String getStyle(SerializerSession session, UserStatus value) { + switch(value) { + case ACTIVE: return "background-color:#5cb85c;text-align:center;vertical-align:middle;"; + case INACTIVE: return "background-color:#888;text-align:center;vertical-align:middle;"; + default: return ""; + } + } + } +} diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java new file mode 100755 index 0000000..3b1ff90 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/dto/package-info.java @@ -0,0 +1,18 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** + +/** + * Examples + */ +package org.apache.juneau.petstore.dto; + diff --git a/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java new file mode 100755 index 0000000..7f2bf15 --- /dev/null +++ b/juneau-petstore-api/src/main/java/org/apache/juneau/petstore/package-info.java @@ -0,0 +1,18 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** + +/** + * Examples + */ +package org.apache.juneau.petstore; + diff --git a/juneau-petstore-client/.gitignore b/juneau-petstore-client/.gitignore new file mode 100644 index 0000000..34acf88 --- /dev/null +++ b/juneau-petstore-client/.gitignore @@ -0,0 +1,6 @@ +/target/ +**/.DS_Store +.classpath +.project +/.settings/ +/bin/ diff --git a/juneau-petstore-client/src/assembly/bin.xml b/juneau-petstore-client/src/assembly/bin.xml new file mode 100644 index 0000000..ad917d5 --- /dev/null +++ b/juneau-petstore-client/src/assembly/bin.xml @@ -0,0 +1,58 @@ + + + + + + bin + + zip + + / + true + + + ${basedir}/../juneau-examples-petstore-client + / + + src/main/** + + + + ${basedir} + / + + src/main/** + files/** + .settings/** + .project + *.launch + *.cfg + + + + ${basedir}/build-overlay + / + true + + + + \ No newline at end of file diff --git a/juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java b/juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java new file mode 100644 index 0000000..d005383 --- /dev/null +++ b/juneau-petstore-client/src/main/java/org/apache/juneau/petstore/Main.java @@ -0,0 +1,112 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore; + +import static java.text.MessageFormat.*; + +import java.io.*; +import java.util.*; + +import org.apache.juneau.json.*; +import org.apache.juneau.marshall.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.petstore.dto.*; +import org.apache.juneau.rest.client.*; + +/** + * Example code showing how to connect to the PetStore application using a remote proxy. + * + *

+ * The remote proxy allows you to make REST calls against our REST interface through Java interface method calls. + */ +public class Main { + + private static final JsonParser JSON_PARSER = JsonParser.create().ignoreUnknownBeanProperties().build(); + + public static void main(String[] args) { + + // Create a RestClient with JSON serialization support. + try (RestClient rc = RestClient.create(SimpleJsonSerializer.class, JsonParser.class).build()) { + + // Instantiate our proxy. + PetStore petStore = rc.getRemoteResource(PetStore.class, "http://localhost:5000"); + + // Print out the pets in the store. + Collection pets = petStore.getPets(); + + // Pretty-print them to SYSOUT. + SimpleJson.DEFAULT_READABLE.println(pets); + + // Initialize the application through REST calls. + init(new PrintWriter(System.out), petStore); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Initialize the petstore database by using a remote resource interface against our REST. + * + * @param w Console output. + * @return This object (for method chaining). + * @throws ParseException Malformed input encountered. + * @throws IOException Thrown by client stream. + */ + public static void init(PrintWriter w, PetStore ps) throws ParseException, IOException { + + for (Pet x : ps.getPets()) { + ps.deletePet("apiKey", x.getId()); + w.println(format("Deleted pet: id={0}", x.getId())); + } + + for (Order x : ps.getOrders()) { + ps.deleteOrder(x.getId()); + w.println(format("Deleted order: id={0}", x.getId())); + } + + for (User x : ps.getUsers()) { + ps.deleteUser(x.getUsername()); + w.println(format("Deleted user: username={0}", x.getUsername())); + } + + for (CreatePet x : load("init/Pets.json", CreatePet[].class)) { + long id = ps.createPet(x); + w.println(format("Created pet: id={0}, name={1}", id, x.getName())); + } + + for (Order x : load("init/Orders.json", Order[].class)) { + long id = ps.placeOrder(x.getPetId(), x.getUsername()); + w.println(format("Created order: id={0}", id)); + } + + for (User x : load("init/Users.json", User[].class)) { + ps.createUser(x); + w.println(format("Created user: username={0}", x.getUsername())); + } + + w.flush(); + } + + //----------------------------------------------------------------------------------------------------------------- + // Helper methods + //----------------------------------------------------------------------------------------------------------------- + + private static T load(String fileName, Class c) throws ParseException, IOException { + return JSON_PARSER.parse(getStream(fileName), c); + } + + private static InputStream getStream(String fileName) { + return Main.class.getResourceAsStream(fileName); + } +} diff --git a/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json new file mode 100644 index 0000000..b306aa8 --- /dev/null +++ b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Orders.json @@ -0,0 +1,18 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** + +[ + {id:101,petId:101,shipDate:'2018-01-01',status:'PLACED'}, + {id:102,petId:102,shipDate:'2018-01-01',status:'APPROVED'}, + {id:103,petId:103,shipDate:'2018-01-01',status:'DELIVERED'} +] diff --git a/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json new file mode 100644 index 0000000..c0aa31f --- /dev/null +++ b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Pets.json @@ -0,0 +1,24 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** + +[ + {species:'CAT', name:'Mr. Frisky', price:39.99, tags:['friendly'], status:'AVAILABLE'}, + {species:'DOG', name:'Kibbles', price:99.99, tags:['loyal'], status:'AVAILABLE'}, + {species:'RABBIT', name:'Hoppy', price:49.99, tags:['friendly','smells nice'], status:'AVAILABLE'}, + {species:'RABBIT', name:'Hoppy 2', price:49.99, status:'AVAILABLE'}, + {species:'RABBIT', name:'Hoppy 3', price:49.99, status:'AVAILABLE'}, + {species:'RABBIT', name:'Hoppy 4', price:49.99, status:'AVAILABLE'}, + {species:'FISH', name:'Gorton', price:1.99, status:'PENDING'}, + {species:'MOUSE', name:'Hackwrench', price:4.99, status:'SOLD'}, + {species:'SNAKE', name:'Just Snake', price:9.99, status:'SOLD'} +] \ No newline at end of file diff --git a/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json new file mode 100644 index 0000000..7f02a3c --- /dev/null +++ b/juneau-petstore-client/src/main/resources/org/apache/juneau/petstore/init/Users.json @@ -0,0 +1,18 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** + +[ + {username:'mwatson',firstName:'Marie',lastName:'Watson',email:'marie.watson@fakemail.com',password:'123456',phone:'444-555-7777',userStatus:'ACTIVE'}, + {username:'dvaughn',firstName:'Daniel',lastName:'Vaughn',email:'daniel.vaughn@test.com',password:'123456',phone:'666-777-3333',userStatus:'ACTIVE'}, + {username:'bfuller',firstName:'Brenda',lastName:'Fuller',email:'brenda.fuller@example.com',password:'123456',phone:'777-888-3333',userStatus:'INACTIVE'} +] diff --git a/juneau-petstore-server/.gitignore b/juneau-petstore-server/.gitignore new file mode 100644 index 0000000..aefe663 --- /dev/null +++ b/juneau-petstore-server/.gitignore @@ -0,0 +1,6 @@ +/target/ +**/.DS_Store +.classpath +.project +/.settings/ +/bin/ \ No newline at end of file diff --git a/juneau-petstore-server/juneau-examples-petstore-server.launch b/juneau-petstore-server/juneau-examples-petstore-server.launch new file mode 100644 index 0000000..bba6035 --- /dev/null +++ b/juneau-petstore-server/juneau-examples-petstore-server.launch @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/juneau-petstore-server/src/assembly/bin.xml b/juneau-petstore-server/src/assembly/bin.xml new file mode 100644 index 0000000..491e69e --- /dev/null +++ b/juneau-petstore-server/src/assembly/bin.xml @@ -0,0 +1,58 @@ + + + + + + bin + + zip + + / + true + + + ${basedir}/../juneau-examples-petstore-server + / + + src/main/** + + + + ${basedir} + / + + src/main/** + files/** + .settings/** + .project + *.launch + *.cfg + + + + ${basedir}/build-overlay + / + true + + + + \ No newline at end of file diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java new file mode 100644 index 0000000..f04953b --- /dev/null +++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/App.java @@ -0,0 +1,34 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore; + +import org.apache.juneau.rest.springboot.JuneauRestInitializer; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +/** + * Entry point for PetStore application. + */ +@SpringBootApplication +public class App { + + public static void main(String[] args) { + new App().start(args); + } + + protected void start(String[] args) { + new SpringApplicationBuilder(App.class) + .initializers(new JuneauRestInitializer(App.class)) // Needed for Juneau resources as injectible Spring beans. + .run(args); + } +} diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java new file mode 100644 index 0000000..d3d7370 --- /dev/null +++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/AppConfiguration.java @@ -0,0 +1,62 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore; + +import org.apache.juneau.petstore.rest.*; +import org.apache.juneau.petstore.service.*; +import org.apache.juneau.rest.springboot.annotation.JuneauRestRoot; +import org.springframework.boot.web.servlet.*; +import org.springframework.context.annotation.*; +import org.springframework.web.filter.*; + +@Configuration +public class AppConfiguration { + + //----------------------------------------------------------------------------------------------------------------- + // Services + //----------------------------------------------------------------------------------------------------------------- + + @Bean + public PetStoreService petStoreService() { + return new PetStoreService(); + } + + //----------------------------------------------------------------------------------------------------------------- + // REST + //----------------------------------------------------------------------------------------------------------------- + + @Bean + @JuneauRestRoot + public RootResources rootResources() { + return new RootResources(); + } + + @Bean + public PetStoreResource petStoreResource() { + return new PetStoreResource(); + } + + /** + * We want to be able to consume url-encoded-form-post bodies, but HiddenHttpMethodFilter triggers the HTTP + * body to be consumed. So disable it. + * + * @param filter The filter. + * @return Filter registration bean. + */ + @Bean + public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) { + FilterRegistrationBean registration = new FilterRegistrationBean<>(filter); + registration.setEnabled(false); + return registration; + } +} diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java new file mode 100644 index 0000000..de79d12 --- /dev/null +++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/PetStoreResource.java @@ -0,0 +1,541 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the 'License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.rest; + +import static org.apache.juneau.dto.swagger.ui.SwaggerUI.*; +import static org.apache.juneau.http.HttpMethodName.*; +import static org.apache.juneau.http.response.Ok.*; + +import java.util.*; +import java.util.Map; + +import javax.inject.*; + +import org.apache.juneau.jsonschema.annotation.*; +import org.apache.juneau.petstore.*; +import org.apache.juneau.petstore.dto.*; +import org.apache.juneau.petstore.service.*; +import org.apache.juneau.*; +import org.apache.juneau.annotation.*; +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.rest.annotation.*; +import org.apache.juneau.http.exception.*; +import org.apache.juneau.rest.helper.*; +import org.apache.juneau.http.response.*; +import org.apache.juneau.rest.widget.*; +import org.apache.juneau.transforms.*; +import org.apache.juneau.rest.converters.*; + +/** + * Sample Petstore application. + * + *

    + *
+ */ +@RestResource( + path="/petstore", + title="Petstore application", + description={ + "This is a sample server Petstore server based on the Petstore sample at Swagger.io.", + "You can find out more about Swagger at http://swagger.io.", + }, + properties= { + // Resolve recursive references when showing schema info in the swagger. + @Property(name=SWAGGERUI_resolveRefsMaxDepth, value="99") + }, + swagger=@ResourceSwagger( + version="1.0.0", + title="Swagger Petstore", + termsOfService="You are on your own.", + contact=@Contact( + name="Juneau Development Team", + email="dev@juneau.apache.org", + url="http://juneau.apache.org" + ), + license=@License( + name="Apache 2.0", + url="http://www.apache.org/licenses/LICENSE-2.0.html" + ), + externalDocs=@ExternalDocs( + description="Find out more about Juneau", + url="http://juneau.apache.org" + ), + tags={ + @Tag( + name="pet", + description="Everything about your Pets", + externalDocs=@ExternalDocs( + description="Find out more", + url="http://juneau.apache.org" + ) + ), + @Tag( + name="store", + description="Access to Petstore orders" + ), + @Tag( + name="user", + description="Operations about user", + externalDocs=@ExternalDocs( + description="Find out more about our store", + url="http://juneau.apache.org" + ) + ) + } + ), + staticFiles={"htdocs:/htdocs"} // Expose static files in htdocs subpackage. +) +@HtmlDocConfig( + widgets={ + ContentTypeMenuItem.class, + ThemeMenuItem.class, + }, + navlinks={ + "up: request:/..", + "options: servlet:/?method=OPTIONS", + "$W{ContentTypeMenuItem}", + "$W{ThemeMenuItem}", + "source: $C{Source/gitHub}/org/apache/juneau/petstore/rest/$R{servletClassSimple}.java" + }, + head={ + "" // Add a cat icon to the page. + }, + header={ + "

$R{resourceTitle}

", + "

$R{methodSummary}

", + "$C{PetStore/headerImage}" + }, + aside={ + "
", + "

This page shows a standard nested REST resource.

", + "

It shows how different properties can be rendered on the same bean in different views.

", + "

It also shows examples of HtmlRender classes and @BeanProperty(format) annotations.

", + "

It also shows how the Queryable converter and query widget can be used to create searchable interfaces.

", + "
" + }, + stylesheet="servlet:/htdocs/themes/dark.css" // Use dark theme by default. +) +public class PetStoreResource extends BasicRest implements PetStore { + + @Inject + private PetStoreService store; + + /** + * Navigation page + * + * @return Navigation page contents. + */ + @RestMethod( + name=GET, + path="/", + summary="Navigation page" + ) + @HtmlDocConfig( + style={ + "INHERIT", // Flag for inheriting resource-level CSS. + "body { ", + "background-image: url('petstore/htdocs/background.jpg'); ", + "background-color: black; ", + "background-size: cover; ", + "background-attachment: fixed; ", + "}" + } + ) + public ResourceDescriptions getTopPage() { + return new ResourceDescriptions() + .append("pet", "All pets in the store") + .append("store", "Orders and inventory") + .append("user", "Petstore users") + ; + } + + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Pets + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + @Override /* PetStore */ + @RestMethod( + name=GET, + path="/pet", + summary="All pets in the store", + swagger=@MethodSwagger( + tags="pet", + parameters={ + Queryable.SWAGGER_PARAMS + } + ), + converters={Queryable.class} + ) + @BeanConfig( + bpx="Pet: tags,photo" + ) + public Collection getPets() throws NotAcceptable { + return store.getPets(); + } + + @Override /* PetStore */ + @RestMethod( + name=GET, + path="/pet/{petId}", + summary="Find pet by ID", + description="Returns a single pet", + swagger=@MethodSwagger( + tags="pet", + value={ + "security:[ { api_key:[] } ]" + } + ) + ) + public Pet getPet(long petId) throws IdNotFound, NotAcceptable { + return store.getPet(petId); + } + + @Override /* PetStore */ + @RestMethod( + name=POST, + path="/pet", + summary="Add a new pet to the store", + swagger=@MethodSwagger( + tags="pet", + value={ + "security:[ { petstore_auth:['write:pets','read:pets'] } ]" + } + ) + ) + public long createPet(CreatePet pet) throws IdConflict, NotAcceptable, UnsupportedMediaType { + return store.create(pet).getId(); + } + + @Override /* PetStore */ + @RestMethod( + name=PUT, + path="/pet/{petId}", + summary="Update an existing pet", + swagger=@MethodSwagger( + tags="pet", + value={ + "security:[ { petstore_auth: ['write:pets','read:pets'] } ]" + } + ) + ) + public Ok updatePet(UpdatePet pet) throws IdNotFound, NotAcceptable, UnsupportedMediaType { + store.update(pet); + return OK; + } + + @Override /* PetStore */ + @RestMethod( + name=GET, + path="/pet/findByStatus", + summary="Finds Pets by status", + description="Multiple status values can be provided with comma separated strings.", + swagger=@MethodSwagger( + tags="pet", + value={ + "security:[{petstore_auth:['write:pets','read:pets']}]" + } + ) + ) + public Collection findPetsByStatus(PetStatus[] status) throws NotAcceptable { + return store.getPetsByStatus(status); + } + + @Override /* PetStore */ + @RestMethod( + name=GET, + path="/pet/findByTags", + summary="Finds Pets by tags", + description="Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + swagger=@MethodSwagger( + tags="pet", + value={ + "security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]" + } + ) + ) + @Deprecated + public Collection findPetsByTags(String[] tags) throws InvalidTag, NotAcceptable { + return store.getPetsByTags(tags); + } + + @Override /* PetStore */ + @RestMethod( + name=DELETE, + path="/pet/{petId}", + summary="Deletes a pet", + swagger=@MethodSwagger( + tags="pet", + value={ + "security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]" + } + ) + ) + public Ok deletePet(String apiKey, long petId) throws IdNotFound, NotAcceptable { + store.removePet(petId); + return OK; + } + + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Orders + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + /** + * Store navigation page. + * + * @return Store navigation page contents. + */ + @RestMethod( + summary="Store navigation page", + swagger=@MethodSwagger( + tags="store" + ) + ) + public ResourceDescriptions getStore() { + return new ResourceDescriptions() + .append("store/order", "Petstore orders") + .append("store/inventory", "Petstore inventory") + ; + } + + @Override + @RestMethod( + name=GET, + path="/store/order", + summary="Petstore orders", + swagger=@MethodSwagger( + tags="store" + ) + ) + @HtmlDocConfig( + widgets={ + QueryMenuItem.class + }, + navlinks={ + "INHERIT", // Inherit links from class. + "[2]:$W{QueryMenuItem}", // Insert QUERY link in position 2. + "[3]:$W{AddOrderMenuItem}" // Insert ADD link in position 3. + } + ) + public Collection getOrders() throws NotAcceptable { + return store.getOrders(); + } + + @Override + @RestMethod( + name=GET, + path="/store/order/{orderId}", + summary="Find purchase order by ID", + description="Returns a purchase order by ID.", + swagger=@MethodSwagger( + tags="store" + ) + ) + public Order getOrder(long orderId) throws InvalidId, IdNotFound, NotAcceptable { + if (orderId < 1 || orderId > 1000) + throw new InvalidId(); + return store.getOrder(orderId); + } + + @Override + @RestMethod( + name=POST, + path="/store/order", + summary="Place an order for a pet", + swagger=@MethodSwagger( + tags="store" + ), + pojoSwaps={ + TemporalDateSwap.IsoLocalDate.class + } + ) + public long placeOrder(long petId, String username) throws IdConflict, NotAcceptable, UnsupportedMediaType { + CreateOrder co = new CreateOrder(petId, username); + return store.create(co).getId(); + } + + @Override + @RestMethod( + name=DELETE, + path="/store/order/{orderId}", + summary="Delete purchase order by ID", + description= { + "For valid response try integer IDs with positive integer value.", + "Negative or non-integer values will generate API errors." + }, + swagger=@MethodSwagger( + tags="store" + ) + ) + public Ok deleteOrder(long orderId) throws InvalidId, IdNotFound, NotAcceptable { + if (orderId < 0) + throw new InvalidId(); + store.removeOrder(orderId); + return OK; + } + + @Override + @RestMethod( + name=GET, + path="/store/inventory", + summary="Returns pet inventories by status", + description="Returns a map of status codes to quantities", + swagger=@MethodSwagger( + tags="store", + responses={ + "200:{ 'x-example':{AVAILABLE:123} }", + }, + value={ + "security:[ { api_key:[] } ]" + } + ) + ) + public Map getStoreInventory() throws NotAcceptable { + return store.getInventory(); + } + + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Users + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + @Override + @RestMethod( + name=GET, + path="/user", + summary="Petstore users", + bpx="User: email,password,phone", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Collection getUsers() throws NotAcceptable { + return store.getUsers(); + } + + @Override + @RestMethod( + name=GET, + path="/user/{username}", + summary="Get user by user name", + swagger=@MethodSwagger( + tags="user" + ) + ) + public User getUser(String username) throws InvalidUsername, IdNotFound, NotAcceptable { + return store.getUser(username); + } + + @Override + @RestMethod( + name=POST, + path="/user", + summary="Create user", + description="This can only be done by the logged in user.", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Ok createUser(User user) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType { + store.create(user); + return OK; + } + + @Override + @RestMethod( + name=POST, + path="/user/createWithArray", + summary="Creates list of users with given input array", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Ok createUsers(User[] users) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType { + for (User user : users) + store.create(user); + return OK; + } + + @Override + @RestMethod( + name=PUT, + path="/user/{username}", + summary="Update user", + description="This can only be done by the logged in user.", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Ok updateUser(String username, User user) throws InvalidUsername, IdNotFound, NotAcceptable, UnsupportedMediaType { + store.update(user); + return OK; + } + + @Override + @RestMethod( + name=DELETE, + path="/user/{username}", + summary="Delete user", + description="This can only be done by the logged in user.", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Ok deleteUser(String username) throws InvalidUsername, IdNotFound, NotAcceptable { + store.removeUser(username); + return OK; + } + + @Override + @RestMethod( + name=GET, + path="/user/login", + summary="Logs user into the system", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Ok login( + String username, + String password, + Value rateLimit, + Value expiresAfter + ) throws InvalidLogin, NotAcceptable { + + RestRequest req = getRequest(); + + if (! store.isValid(username, password)) + throw new InvalidLogin(); + + Date d = new Date(System.currentTimeMillis() + 30 * 60 * 1000); + req.getSession().setAttribute("login-expires", d); + rateLimit.set(1000); + expiresAfter.set(new ExpiresAfter(d)); + return OK; + } + + @Override + @RestMethod( + name=GET, + path="/user/logout", + summary="Logs out current logged in user session", + swagger=@MethodSwagger( + tags="user" + ) + ) + public Ok logout() throws NotAcceptable { + getRequest().getSession().removeAttribute("login-expires"); + return OK; + } +} \ No newline at end of file diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java new file mode 100644 index 0000000..a92d9de --- /dev/null +++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/rest/RootResources.java @@ -0,0 +1,66 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.rest; + +import org.apache.juneau.html.annotation.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.rest.annotation.*; +import org.apache.juneau.rest.widget.*; +import org.apache.juneau.serializer.annotation.*; + +/** + * Sample REST resource showing how to implement a "router" resource page. + * + *
    + *
+ */ +@RestResource( + path="/*", + title="Root resources", + description="Example of a router resource page.", + children={ + PetStoreResource.class + } +) +@HtmlDocConfig( + widgets={ + ContentTypeMenuItem.class, + ThemeMenuItem.class + }, + navlinks={ + "options: ?method=OPTIONS", + "$W{ContentTypeMenuItem}", + "$W{ThemeMenuItem}", + "source: $C{Source/gitHub}/org/apache/juneau/petstore/rest/$R{servletClassSimple}.java" + }, + aside={ + "
", + "

This is an example of a 'router' page that serves as a jumping-off point to child resources.

", + "

Resources can be nested arbitrarily deep through router pages.

", + "

Note the options link provided that lets you see the generated swagger doc for this page.

", + "

Also note the sources link on these pages to view the source code for the page.

", + "

All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.

", + "

Other features (such as this aside) are added through annotations.

", + "
" + } +) +@SerializerConfig( + // For testing purposes, we want to use single quotes in all the serializers so it's easier to do simple + // String comparisons. + // You can apply any of the Serializer/Parser/BeanContext settings this way. + quoteChar="'" +) +public class RootResources extends BasicRestServletGroup { + private static final long serialVersionUID = 1L; +} diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java new file mode 100644 index 0000000..4e2aedf --- /dev/null +++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/AbstractPersistenceService.java @@ -0,0 +1,273 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.service; + +import java.util.*; + +import javax.persistence.*; + +import org.apache.juneau.pojotools.*; + +/** + * Superclass for DAOs that use the JPA entity manager. + * + *
    + *
+ */ +public class AbstractPersistenceService { + + private final EntityManagerFactory entityManagerFactory; + + /** + * Constructor. + */ + public AbstractPersistenceService() { + entityManagerFactory = Persistence.createEntityManagerFactory("test"); + } + + /** + * Retrieves an entity manager session. + * + * @return The entity manager session. + */ + protected EntityManager getEntityManager() { + return entityManagerFactory.createEntityManager(); + } + + /** + * Retrieves the specified JPA bean from the repository. + * + * @param em The entity manager to use to retrieve the bean. + * @param t The bean type to retrieve. + * @param id The primary key value. + * @return The JPA bean, or null if not found. + */ + protected T find(EntityManager em, Class t, Object id) { + return em.find(t, id); + } + + /** + * Same as {@link #find(EntityManager, Class, Object)} but uses a new entity manager. + * + * @param t The bean type to retrieve. + * @param id The primary key value. + * @return The JPA bean, or null if not found. + */ + protected T find(Class t, Object id) { + return find(getEntityManager(), t, id); + } + + /** + * Store the specified JPA bean in the repository. + * + * @param em The entity manager to use to store and merge the bean. + * @param t The bean to store. + * @return The merged JPA bean returned by the {@link EntityManager#merge(Object)} method, or null if the bean was null. + */ + protected T merge(EntityManager em, T t) { + if (t == null) + return null; + try { + EntityTransaction et = em.getTransaction(); + et.begin(); + t = em.merge(t); + et.commit(); + return t; + } finally { + em.close(); + } + } + + /** + * Same as {@link #merge(EntityManager, Object)} but uses a new entity manager. + * + * @param t The bean to store. + * @return The merged JPA bean returned by the {@link EntityManager#merge(Object)} method, or null if the bean was null. + */ + protected T merge(T t) { + return merge(getEntityManager(), t); + } + + /** + * Store the specified JPA beans in the repository. + * + * All values are persisted in the same transaction. + * + * @param em The entity manager to use to store and merge the beans. + * @param c The collection of beans to store. + * @return The merged JPA beans returned by the {@link EntityManager#merge(Object)} method. + */ + protected Collection merge(EntityManager em, Collection c) { + Collection c2 = new ArrayList<>(); + try { + EntityTransaction et = em.getTransaction(); + et.begin(); + for (T t : c) + c2.add(em.merge(t)); + et.commit(); + return c2; + } finally { + em.close(); + } + } + + /** + * Same as {@link #merge(EntityManager, Collection)} but uses a new entity manager. + * + * @param c The collection of beans to store. + * @return The merged JPA beans returned by the {@link EntityManager#merge(Object)} method. + */ + protected Collection merge(Collection c) { + return merge(getEntityManager(), c); + } + + /** + * Remove the specified JPA bean from the repository. + * + * @param t The bean type to remove. + * @param id The primary key value. + */ + protected void remove(Class t, Object id) { + EntityManager em = getEntityManager(); + remove(em, find(em, t, id)); + } + + /** + * Remove the specified JPA bean from the repository. + * + * @param em The entity manager used to retrieve the bean. + * @param t The bean to remove. Can be null. + */ + protected void remove(EntityManager em, T t) { + if (t == null) + return; + try { + EntityTransaction et = em.getTransaction(); + et.begin(); + em.remove(t); + et.commit(); + } finally { + em.close(); + } + } + + /** + * Runs a JPA query and returns the results. + * + * @param The bean type. + * @param em The entity manager to use to retrieve the beans. + * @param query The JPA query. + * @param t The bean type. + * @param searchArgs Optional search arguments. + * @return The results. + */ + protected List query(EntityManager em, String query, Class t, SearchArgs searchArgs, PageArgs pageArgs) { + TypedQuery q = em.createQuery(query, t); + if (pageArgs != null) { + q.setMaxResults(pageArgs.getLimit() == 0 ? 100 : pageArgs.getLimit()); + q.setFirstResult(pageArgs.getPosition()); + } + return em.createQuery(query, t).getResultList(); + } + + /** + * Same as {@link #query(EntityManager,String,Class,SearchArgs)} but uses a new entity manager. + * + * @param The bean type. + * @param query The JPA query. + * @param t The bean type. + * @param searchArgs Optional search arguments. + * @return The results. + */ + protected List query(String query, Class t, SearchArgs searchArgs, PageArgs pageArgs) { + return query(getEntityManager(), query, t, searchArgs, pageArgs); + } + + /** + * Runs a JPA parameterized query and returns the results. + * + * @param em The entity manager to use to retrieve the beans. + * @param query The JPA query. + * @param t The bean type. + * @param params The query parameter values. + * @return The results. + */ + protected List query(EntityManager em, String query, Class t, Map params) { + TypedQuery tq = em.createQuery(query, t); + for (Map.Entry e : params.entrySet()) { + tq.setParameter(e.getKey(), e.getValue()); + } + return tq.getResultList(); + } + + /** + * Same as {@link #query(EntityManager,String,Class,Map)} but uses a new entity manager. + * + * @param query The JPA query. + * @param t The bean type. + * @param params The query parameter values. + * @return The results. + */ + protected List query(String query, Class t, Map params) { + return query(getEntityManager(), query, t, params); + } + + /** + * Runs a JPA update statement. + * + * @param em The entity manager to use to run the statement. + * @param query The JPA update statement. + * @return The number of rows modified. + */ + protected int update(EntityManager em, String query) { + return em.createQuery(query).executeUpdate(); + } + + /** + * Same as {@link #update(EntityManager,String)} but uses a new entity manager. + * + * @param query The JPA update statement. + * @return The number of rows modified. + */ + protected int update(String query) { + return update(getEntityManager(), query); + } + + /** + * Runs a JPA parameterized update statement. + * + * @param em The entity manager to use to run the statement. + * @param query The JPA update statement. + * @param params The query parameter values. + * @return The number of rows modified. + */ + protected int update(EntityManager em, String query, Map params) { + Query q = em.createQuery(query); + for (Map.Entry e : params.entrySet()) { + q.setParameter(e.getKey(), e.getValue()); + } + return q.executeUpdate(); + } + + /** + * Same as {@link #update(EntityManager,String,Map)} but uses a new entity manager. + * + * @param query The JPA update statement. + * @param params The query parameter values. + * @return The number of rows modified. + */ + protected int update(String query, Map params) { + return update(getEntityManager(), query, params); + } +} diff --git a/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java new file mode 100644 index 0000000..ac83c4c --- /dev/null +++ b/juneau-petstore-server/src/main/java/org/apache/juneau/petstore/service/PetStoreService.java @@ -0,0 +1,329 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.petstore.service; + +import static java.text.MessageFormat.*; + +import java.io.*; +import java.util.*; + +import javax.persistence.*; + +import org.apache.juneau.json.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.petstore.dto.*; +import org.apache.juneau.pojotools.*; +import org.apache.juneau.pojotools.SearchArgs; + +/** + * Pet store database application. + *

+ * Uses JPA persistence to store and retrieve PetStore DTOs. + * JPA beans are defined in META-INF/persistence.xml. + * + *

    + *
+ */ +public class PetStoreService extends AbstractPersistenceService { + + //----------------------------------------------------------------------------------------------------------------- + // Initialization methods. + //----------------------------------------------------------------------------------------------------------------- + + /** + * Initialize the petstore database using JPA. + * + * @param w Console output. + * @return This object (for method chaining). + * @throws ParseException Malformed input encountered. + * @throws IOException File could not be read from file system. + */ + public PetStoreService initDirect(PrintWriter w) throws ParseException, IOException { + + EntityManager em = getEntityManager(); + EntityTransaction et = em.getTransaction(); + JsonParser parser = JsonParser.create().build(); + + et.begin(); + + for (Pet x : em.createQuery("select X from PetstorePet X", Pet.class).getResultList()) { + em.remove(x); + w.println(format("Deleted pet: id={0}", x.getId())); + } + for (Order x : em.createQuery("select X from PetstoreOrder X", Order.class).getResultList()) { + em.remove(x); + w.println(format("Deleted order: id={0}", x.getId())); + } + for (User x : em.createQuery("select X from PetstoreUser X", User.class).getResultList()) { + em.remove(x); + w.println(format("Deleted user: username={0}", x.getUsername())); + } + + et.commit(); + et.begin(); + + for (Pet x : parser.parse(getStream("init/Pets.json"), Pet[].class)) { + x = em.merge(x); + w.println(format("Created pet: id={0}, name={1}", x.getId(), x.getName())); + } + for (Order x : parser.parse(getStream("init/Orders.json"), Order[].class)) { + x = em.merge(x); + w.println(format("Created order: id={0}", x.getId())); + } + for (User x: parser.parse(getStream("init/Users.json"), User[].class)) { + x = em.merge(x); + w.println(format("Created user: username={0}", x.getUsername())); + } + + et.commit(); + + return this; + } + + + //----------------------------------------------------------------------------------------------------------------- + // Service methods. + //----------------------------------------------------------------------------------------------------------------- + + /** + * Returns the pet with the specified ID. + * + * @param id The pet ID. + * @return The pet with the specified ID. Never null. + * @throws IdNotFound If pet was not found. + */ + public Pet getPet(long id) throws IdNotFound { + return find(Pet.class, id); + } + + /** + * Returns the order with the specified ID. + * + * @param id The order ID. + * @return The order with the specified ID. Never null. + * @throws IdNotFound If order was not found. + */ + public Order getOrder(long id) throws IdNotFound { + return find(Order.class, id); + } + + /** + * Returns the user with the specified username. + * + * @param username The username. + * @return The user with the specified username. Never null. + * @throws InvalidUsername Username was not valid. + * @throws IdNotFound If order was not found. + */ + public User getUser(String username) throws InvalidUsername, IdNotFound { + assertValidUsername(username); + return find(User.class, username); + } + + /** + * Returns all pets in the database. + * + * @return All pets in the database. + */ + public List getPets() { + return query("select X from PetstorePet X", Pet.class, (SearchArgs)null, (PageArgs)null); + } + + /** + * Returns all orders in the database. + * + * @return All orders in the database. + */ + public List getOrders() { + return query("select X from PetstoreOrder X", Order.class, (SearchArgs)null, (PageArgs)null); + } + + /** + * Returns all users in the database. + * + * @return All users in the database. + */ + public List getUsers() { + return query("select X from PetstoreUser X", User.class, (SearchArgs)null, (PageArgs)null); + } + + /** + * Creates a new pet in the database. + * + * @param c The pet input data. + * @return a new {@link Pet} object. + */ + public Pet create(CreatePet c) { + return merge(new Pet().status(PetStatus.AVAILABLE).apply(c)); + } + + /** + * Creates a new order in the database. + * + * @param c The order input data. + * @return a new {@link Order} object. + */ + public Order create(CreateOrder c) { + return merge(new Order().status(OrderStatus.PLACED).apply(c)); + } + + /** + * Creates a new user in the database. + * + * @param c The user input data. + * @return a new {@link User} object. + */ + public User create(User c) { + return merge(new User().apply(c)); + } + + /** + * Updates a pet in the database. + * + * @param u The update information. + * @return The updated {@link Pet} object. + * @throws IdNotFound Pet was not found. + */ + public Pet update(UpdatePet u) throws IdNotFound { + EntityManager em = getEntityManager(); + return merge(em, find(em, Pet.class, u.getId()).apply(u)); + } + + /** + * Updates an order in the database. + * + * @param o The update information. + * @return The updated {@link Order} object. + * @throws IdNotFound Order was not found. + */ + public Order update(Order o) throws IdNotFound { + EntityManager em = getEntityManager(); + return merge(em, find(em, Order.class, o.getId()).apply(o)); + } + + /** + * Updates a user in the database. + * + * @param u The update information. + * @return The updated {@link User} object. + * @throws IdNotFound User was not found. + * @throws InvalidUsername The username was not valid. + */ + public User update(User u) throws IdNotFound, InvalidUsername { + assertValidUsername(u.getUsername()); + EntityManager em = getEntityManager(); + return merge(em, find(em, User.class, u.getUsername()).apply(u)); + } + + /** + * Removes a pet from the database. + * + * @param id The pet ID. + * @throws IdNotFound Pet was not found. + */ + public void removePet(long id) throws IdNotFound { + EntityManager em = getEntityManager(); + remove(em, find(em, Pet.class, id)); + } + + /** + * Removes an order from the database. + * + * @param id The order ID. + * @throws IdNotFound Order was not found. + */ + public void removeOrder(long id) throws IdNotFound { + EntityManager em = getEntityManager(); + remove(em, find(em, Order.class, id)); + } + + /** + * Removes a user from the database. + * + * @param username The username. + * @throws IdNotFound User was not found. + */ + public void removeUser(String username) throws IdNotFound { + EntityManager em = getEntityManager(); + remove(em, find(em, User.class, username)); + } + + /** + * Returns all pets with the specified statuses. + * + * @param status Pet statuses. + * @return Pets with the specified statuses. + */ + public Collection getPetsByStatus(PetStatus[] status) { + return getEntityManager() + .createQuery("select X from PetstorePet X where X.status in :status", Pet.class) + .setParameter("status", status) + .getResultList(); + } + + /** + * Returns all pets with the specified tags. + * + * @param tags Pet tags. + * @return Pets with the specified tags. + * @throws InvalidTag Tag name was invalid. + */ + public Collection getPetsByTags(String[] tags) throws InvalidTag { + return getEntityManager() + .createQuery("select X from PetstorePet X where X.tags in :tags", Pet.class) + .setParameter("tags", tags) + .getResultList(); + } + + /** + * Returns a summary of pet statuses and counts. + * + * @return A summary of pet statuses and counts. + */ + public Map getInventory() { + Map m = new LinkedHashMap<>(); + for (Pet p : getPets()) { + PetStatus ps = p.getStatus(); + if (! m.containsKey(ps)) + m.put(ps, 1); + else + m.put(ps, m.get(ps) + 1); + } + return m; + } + + /** + * Returns true if the specified username and password is valid. + * + * @param username The username. + * @param password The password. + * @return true if the specified username and password is valid. + */ + public boolean isValid(String username, String password) { + return getUser(username).getPassword().equals(password); + } + + //----------------------------------------------------------------------------------------------------------------- + // Helper methods + //----------------------------------------------------------------------------------------------------------------- + + private void assertValidUsername(String username) throws InvalidUsername { + if (username == null || ! username.matches("[\\w\\d]{3,8}")) + throw new InvalidUsername(); + } + + private InputStream getStream(String fileName) { + return getClass().getResourceAsStream(fileName); + } +} \ No newline at end of file diff --git a/juneau-petstore-server/src/main/resources/META-INF/persistence.xml b/juneau-petstore-server/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..8db6a41 --- /dev/null +++ b/juneau-petstore-server/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,34 @@ + + + + org.apache.juneau.petstore.dto.Pet + org.apache.juneau.petstore.dto.Order + org.apache.juneau.petstore.dto.User + + + + + + + + + + + + \ No newline at end of file diff --git a/juneau-petstore-server/src/main/resources/application.properties b/juneau-petstore-server/src/main/resources/application.properties new file mode 100644 index 0000000..768c87b --- /dev/null +++ b/juneau-petstore-server/src/main/resources/application.properties @@ -0,0 +1,15 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// **************************************************************************************************************************** + +logging.level.org.springframework=INFO +server.port=5000 diff --git a/juneau-petstore-server/src/main/resources/htdocs/background.jpg b/juneau-petstore-server/src/main/resources/htdocs/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d75bcf13b6215a2300ff2f057ac06ddff04a1cc5 GIT binary patch literal 105889 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 LqX(wiJ}~j$?5I0k literal 0 HcmV?d00001 diff --git a/juneau-petstore-server/src/main/resources/juneau.cfg b/juneau-petstore-server/src/main/resources/juneau.cfg new file mode 100755 index 0000000..98e4574 --- /dev/null +++ b/juneau-petstore-server/src/main/resources/juneau.cfg @@ -0,0 +1,70 @@ +# *************************************************************************************************************************** +# * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +# * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +# * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +# * with the License. You may obtain a copy of the License at * +# * * +# * http://www.apache.org/licenses/LICENSE-2.0 * +# * * +# * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +# * specific language governing permissions and limitations under the License. * +# *************************************************************************************************************************** + +#======================================================================================================================= +# REST settings +#======================================================================================================================= +[REST] + +# Comma-delimited list of key-value pairs that represent locations of static files that can be served up by your @RestResource-annotated +# classes. These are static files that are served up by the servlet under the specified sub-paths. +# For example, given the following setting... +# staticFiles = htdocs:my-docs,styles/my-styles +# ...the URI "/servletPath/htdocs/javadoc.css" resolves to the path "/my-docs/javadoc.css". +# This path can be relative to the working directory, classpath root, or package of your resource class. +# Used by the BasicRestConfig interface that defines the following value: +# staticFiles="$C{REST/staticFiles}" +staticFiles = htdocs:htdocs + +# Stylesheet to use for HTML views. +# Used by the BasicRestConfig interface that defines the following value: +# stylesheet="$C{REST/theme,servlet:/htdocs/themes/devops.css}" +theme = servlet:/htdocs/themes/devops.css + +# Various look-and-feel settings used in the BasicRestConfig interface. +headerIcon = servlet:/htdocs/images/juneau.png +headerLink = http://juneau.apache.org +footerIcon = servlet:/htdocs/images/asf.png +footerLink = http://www.apache.org +favicon = $C{REST/headerIcon} +head = +header = + + + +footer = + + + + +#======================================================================================================================= +# SqlQueryResource properties +#======================================================================================================================= +[SqlQueryResource] +driver = org.apache.derby.jdbc.EmbeddedDriver +directory = target/derby/testDB +connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true +allowTempUpdates = true +includeRowNums = false + +#======================================================================================================================= +# Source code location +#======================================================================================================================= +[Source] +gitHub = https://github.com/apache/juneau/blob/master/juneau-examples/juneau-examples-rest/src/main/java + +#======================================================================================================================= +# PetStoreResource properties +#======================================================================================================================= +[PetStore] +headerImage = diff --git a/juneau-petstore-server/src/main/resources/log4j.xml b/juneau-petstore-server/src/main/resources/log4j.xml new file mode 100644 index 0000000..18b0d7c --- /dev/null +++ b/juneau-petstore-server/src/main/resources/log4j.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file