This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push: new 7a91424 PetStore improvements. 7a91424 is described below commit 7a91424e2c611c46d32b5ead6df94c5b0d4dd3bd Author: JamesBognar <jamesbog...@apache.org> AuthorDate: Mon Apr 16 19:06:58 2018 -0400 PetStore improvements. --- .../main/java/org/apache/juneau/utils/IdMap.java | 8 + .../juneau/examples/rest/PetStoreResource.java | 246 --------------------- .../apache/juneau/examples/rest/RootResources.java | 2 +- .../rest/petstore/{Order.java => CreateOrder.java} | 61 ++--- .../juneau/examples/rest/petstore/Order.java | 10 +- .../juneau/examples/rest/petstore/PetStore.java | 43 +++- .../examples/rest/petstore/PetStoreResource.java | 21 +- 7 files changed, 84 insertions(+), 307 deletions(-) diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/IdMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/IdMap.java index a41a6a9..11a7c4e 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/IdMap.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/IdMap.java @@ -95,4 +95,12 @@ public class IdMap<K,V> extends ConcurrentHashMap<K,V> { public K nextId() { return idGen.next(); } + + /** + * Sets a lower bound on the specified ID. + * @param k The lower-bound key. + */ + public void lbId(K k) { + idGen.lb(k); + } } diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java deleted file mode 100644 index ec57bd1..0000000 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PetStoreResource.java +++ /dev/null @@ -1,246 +0,0 @@ -// *************************************************************************************************************************** -// * 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.examples.rest; - -import static org.apache.juneau.dto.html5.HtmlBuilder.*; -import static org.apache.juneau.http.HttpMethodName.*; -import static org.apache.juneau.rest.annotation.HookEvent.*; - -import java.util.*; -import java.util.Map; - -import org.apache.juneau.annotation.*; -import org.apache.juneau.dto.html5.*; -import org.apache.juneau.html.*; -import org.apache.juneau.html.annotation.Html; -import org.apache.juneau.json.*; -import org.apache.juneau.microservice.*; -import org.apache.juneau.rest.*; -import org.apache.juneau.rest.annotation.*; -import org.apache.juneau.rest.annotation.Body; -import org.apache.juneau.rest.converters.*; -import org.apache.juneau.rest.helper.*; -import org.apache.juneau.rest.widget.*; -import org.apache.juneau.serializer.*; -import org.apache.juneau.transforms.*; - -/** - * Sample REST resource that renders summary and detail views of the same bean. - */ -@RestResource( - title="Pet Store", - description="An example of a typical REST resource where beans are rendered in summary and details views.", - path="/petstore", - htmldoc=@HtmlDoc( - widgets={ - ContentTypeMenuItem.class, - ThemeMenuItem.class, - PetStoreResource.AddPet.class - }, - navlinks={ - "up: request:/..", - "options: servlet:/?method=OPTIONS", - "$W{ContentTypeMenuItem}", - "$W{ThemeMenuItem}", - "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java", - "$W{AddPet}" - }, - aside={ - "<div style='max-width:400px' class='text'>", - " <p>This page shows a standard REST resource that renders bean summaries and details.</p>", - " <p>It shows how different properties can be rendered on the same bean in different views.</p>", - " <p>It also shows examples of HtmlRender classes and @BeanProperty(format) annotations.</p>", - " <p>It also shows how the Queryable converter and query widget can be used to create searchable interfaces.</p>", - "</div>" - }, - head={ - "<link rel='icon' href='$U{servlet:/htdocs/cat.png}'/>" - } - ), - staticFiles={"htdocs:htdocs"} -) -public class PetStoreResource extends BasicRestServletJena { - private static final long serialVersionUID = 1L; - - // Our database. - private Map<Integer,Pet> petDB; - - /** - * Initializes the pet store database. - * - * @param builder The resource config. - * @throws Exception - */ - @RestHook(INIT) - public void initDatabase(RestContextBuilder builder) throws Exception { - // Load our database from a local JSON file. - petDB = JsonParser.DEFAULT.parse(getClass().getResourceAsStream("PetStore.json"), LinkedHashMap.class, Integer.class, Pet.class); - } - - // Exclude the 'breed' and 'getsAlongWith' properties from the beans. - @RestMethod( - name=GET, - path="/", - summary="The complete list of pets in the store", - bpx="Pet: breed,getsAlongWith", - - // Add our converter for POJO query support. - converters=Queryable.class, - - // Add our menu items in the nav links. - htmldoc=@HtmlDoc( - - widgets={ - QueryMenuItem.class, - ContentTypeMenuItem.class, - ThemeMenuItem.class - }, - - navlinks={ - "INHERIT", // Inherit links from class. - "[2]:$W{QueryMenuItem}" // Insert QUERY link in position 2. - } - ) - ) - public Collection<Pet> getPets() { - return petDB.values(); - } - - // Shows all bean properties. - @RestMethod(name=GET, path="/{id}", summary="Pet details") - public Pet getPet(@Path("id") Integer id) { - return petDB.get(id); - } - - @RestMethod(name=POST, path="/") - public Redirect addPet(@Body Pet pet) throws Exception { - this.petDB.put(pet.id, pet); - return new Redirect("servlet:/"); - } - - // Our bean class. - public static class Pet { - - @Html(link="servlet:/{id}") // Creates a hyperlink in HTML view. - @NameProperty // Links the parent key to this bean. - public int id; - - public String name; - public Kind kind; - public String breed; - public List<Kind> getsAlongWith; - - @BeanProperty(format="$%.2f") // Renders price in dollars. - public float price; - - @Swap(DateSwap.ISO8601D.class) // Renders dates in ISO8601 format. - public Date birthDate; - - public int getAge() { - Calendar c = new GregorianCalendar(); - c.setTime(birthDate); - return new GregorianCalendar().get(Calendar.YEAR) - c.get(Calendar.YEAR); - } - } - - @Html(render=KindRender.class) // Render as an icon in HTML. - public static enum Kind { - CAT, DOG, BIRD, FISH, MOUSE, RABBIT, SNAKE - } - - public static class KindRender extends HtmlRender<Kind> { - @Override - public Object getContent(SerializerSession session, Kind value) { - return new Img().src("servlet:/htdocs/"+value.toString().toLowerCase()+".png"); - } - @Override - public String getStyle(SerializerSession session, Kind value) { - return "background-color:#FDF2E9"; - } - } - - /** - * Renders the "ADD" menu item. - */ - public class AddPet extends MenuItemWidget { - - @Override - public String getLabel(RestRequest req) throws Exception { - return "add"; - } - - @Override - public Object getContent(RestRequest req) throws Exception { - return div( - form().id("form").action("servlet:/").method(POST).children( - table( - tr( - th("ID:"), - td(input().name("id").type("number").value(getNextAvailableId())), - td(new Tooltip("(?)", "A unique identifer for the pet.", br(), "Must not conflict with existing IDs")) - ), - tr( - th("Name:"), - td(input().name("name").type("text")), - td(new Tooltip("(?)", "The name of the pet.", br(), "e.g. 'Fluffy'")) - ), - tr( - th("Kind:"), - td( - select().name("kind").children( - option("CAT"), option("DOG"), option("BIRD"), option("FISH"), option("MOUSE"), option("RABBIT"), option("SNAKE") - ) - ), - td(new Tooltip("(?)", "The kind of animal.")) - ), - tr( - th("Breed:"), - td(input().name("breed").type("text")), - td(new Tooltip("(?)", "The breed of animal.", br(), "Can be any arbitrary text")) - ), - tr( - th("Gets along with:"), - td(input().name("getsAlongWith").type("text")), - td(new Tooltip("(?)", "A comma-delimited list of other animal types that this animal gets along with.")) - ), - tr( - th("Price:"), - td(input().name("price").type("number").placeholder("1.0").step("0.01").min(1).max(100)), - td(new Tooltip("(?)", "The price to charge for this pet.")) - ), - tr( - th("Birthdate:"), - td(input().name("birthDate").type("date")), - td(new Tooltip("(?)", "The pets birthday.")) - ), - tr( - td().colspan(2).style("text-align:right").children( - button("reset", "Reset"), - button("button","Cancel").onclick("window.location.href='/'"), - button("submit", "Submit") - ) - ) - ).style("white-space:nowrap") - ) - ); - } - } - - final int getNextAvailableId() { - int i = 100; - for (Integer k : petDB.keySet()) - i = Math.max(i, k); - return i+1; - } -} - diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java index fc35343..bbdeafe 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java @@ -15,6 +15,7 @@ package org.apache.juneau.examples.rest; import static org.apache.juneau.serializer.WriterSerializer.*; import org.apache.juneau.examples.rest.addressbook.*; +import org.apache.juneau.examples.rest.petstore.*; import org.apache.juneau.microservice.*; import org.apache.juneau.microservice.resources.*; import org.apache.juneau.rest.annotation.*; @@ -58,7 +59,6 @@ import org.apache.juneau.rest.widget.*; children={ HelloWorldResource.class, PetStoreResource.class, - org.apache.juneau.examples.rest.petstore.PetStoreResource.class, SystemPropertiesResource.class, MethodExampleResource.class, RequestEchoResource.class, diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/CreateOrder.java similarity index 69% copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java copy to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/CreateOrder.java index 43139e0..5bc4bca 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/CreateOrder.java @@ -13,60 +13,35 @@ package org.apache.juneau.examples.rest.petstore; import org.apache.juneau.annotation.*; -import org.apache.juneau.html.annotation.*; -@Bean(fluentSetters=true, properties="id,petId,quantity,shipDate,status") -@Example("{id:123,petId:456,quantity:100,shipDate:'2012-12-21',status:'APPROVED'}") -public class Order { - private long id, petId; - private int quantity; - private String shipDate; - private OrderStatus status; - - public long getId() { - return id; +/** + * Bean for creating {@link Order} objects. + */ +public class CreateOrder { + private final long petId; + private final int quantity; + private final String shipDate; + + @BeanConstructor(properties="petId,quantity,shipDate") + public CreateOrder(long petId, int quantity, String shipDate) { + this.petId = petId; + this.quantity = quantity; + this.shipDate = shipDate; } - @Html(link="servlet:/store/order/{id}") - public Order id(long id) { - this.id = id; - return this; + public static CreateOrder example() { + return new CreateOrder(123, 10, "2012-12-21"); } - - @Html(link="servlet:/pet/{id}") + public long getPetId() { return petId; } - - public Order petId(long petId) { - this.petId = petId; - return this; - } - + public int getQuantity() { return quantity; } - - public Order quantity(int quantity) { - this.quantity = quantity; - return this; - } - + public String getShipDate() { return shipDate; } - - public Order shipDate(String shipDate) { - this.shipDate = shipDate; - return this; - } - - public OrderStatus getStatus() { - return status; - } - - public Order status(OrderStatus status) { - this.status = status; - return this; - } } diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java index 43139e0..9886fc1 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java @@ -12,15 +12,18 @@ // *************************************************************************************************************************** package org.apache.juneau.examples.rest.petstore; +import java.util.*; + import org.apache.juneau.annotation.*; import org.apache.juneau.html.annotation.*; +import org.apache.juneau.transforms.*; @Bean(fluentSetters=true, properties="id,petId,quantity,shipDate,status") @Example("{id:123,petId:456,quantity:100,shipDate:'2012-12-21',status:'APPROVED'}") public class Order { private long id, petId; private int quantity; - private String shipDate; + private Date shipDate; private OrderStatus status; public long getId() { @@ -52,11 +55,12 @@ public class Order { return this; } - public String getShipDate() { + @Swap(DateSwap.ISO8601D.class) + public Date getShipDate() { return shipDate; } - public Order shipDate(String shipDate) { + public Order shipDate(Date shipDate) { this.shipDate = shipDate; return this; } diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java index c7bae5f..7c786f2 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStore.java @@ -17,6 +17,7 @@ import java.util.*; import java.util.concurrent.*; import org.apache.juneau.*; +import org.apache.juneau.internal.*; import org.apache.juneau.json.*; import org.apache.juneau.transform.*; import org.apache.juneau.utils.*; @@ -143,6 +144,8 @@ public class PetStore { public Pet add(Pet value) throws IdConflict { if (value.getId() == 0) value.id(petDb.nextId()); + else + petDb.lbId(value.getId()); Pet old = petDb.putIfAbsent(value.getId(), value); if (old != null) throw new IdConflict(value.getId(), Pet.class); @@ -184,6 +187,39 @@ public class PetStore { return value; } + public Pet create(CreatePet c) { + Pet p = new Pet(); + p.name(c.getName()); + p.price(c.getPrice()); + p.species(getSpecies(c.getName())); + p.tags(getTags(c.getTags())); + p.status(c.getStatus()); + return add(p); + } + + public Order create(CreateOrder c) { + Order o = new Order(); + o.petId(c.getPetId()); + o.quantity(c.getQuantity()); + o.shipDate(StringUtils.parseISO8601Date(c.getShipDate())); + o.status(OrderStatus.PLACED); + return add(o); + } + + private List<Tag> getTags(List<String> tags) { + List<Tag> l = new ArrayList<>(); + for (String t : tags) + l.add(getOrCreateTag(t)); + return l; + } + + private Tag getOrCreateTag(String name) { + for (Tag t : tagDb.values()) + if (t.getName().equals(name)) + return t; + return add(new Tag().name(name)); + } + public Pet update(Pet value) throws IdNotFound { Pet old = petDb.replace(value.getId(), value); if (old == null) @@ -191,13 +227,6 @@ public class PetStore { return value; } - public Species update(Species value) throws IdNotFound { - Species old = speciesDb.replace(value.getId(), value); - if (old == null) - throw new IdNotFound(value.getId(), Species.class); - return value; - } - public Order update(Order value) throws IdNotFound { Order old = orderDb.replace(value.getId(), value); if (old == null) diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java index 1e130fe..dd490d6 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java @@ -31,8 +31,8 @@ import org.apache.juneau.rest.converters.*; * Sample resource that shows how to generate ATOM feeds. */ @RestResource( - path="/petstore2", - title="Swagger Petstore", + path="/petstore", + title="Petstore application", description= "This is a sample server Petstore server based on the Petstore sample at Swagger.io." + "<br>You can find out more about Swagger at <a class='link' href='http://swagger.io'>http://swagger.io</a>.", @@ -55,6 +55,14 @@ import org.apache.juneau.rest.converters.*; "<h1>$R{resourceTitle}</h1>", "<h2>$R{methodSummary}</h2>", "$C{PetStore/headerImage}" + }, + aside={ + "<div style='max-width:400px' class='text'>", + " <p>This page shows a standard nested REST resource.</p>", + " <p>It shows how different properties can be rendered on the same bean in different views.</p>", + " <p>It also shows examples of HtmlRender classes and @BeanProperty(format) annotations.</p>", + " <p>It also shows how the Queryable converter and query widget can be used to create searchable interfaces.</p>", + "</div>" } ), properties= { @@ -107,7 +115,6 @@ public class PetStoreResource extends BasicRestServletJena { QueryMenuItem.class, AddPetMenuItem.class }, - navlinks={ "INHERIT", // Inherit links from class. "[2]:$W{QueryMenuItem}", // Insert QUERY link in position 2. @@ -147,10 +154,10 @@ public class PetStoreResource extends BasicRestServletJena { } ) public Ok addPet( - @Body(description="Pet object that needs to be added to the store") Pet pet + @Body(description="Pet object that needs to be added to the store") CreatePet pet ) throws IdConflict, NotAcceptable, UnsupportedMediaType { - store.add(pet); + store.create(pet); return OK; } @@ -331,10 +338,10 @@ public class PetStoreResource extends BasicRestServletJena { } ) public Order placeOrder( - @Body(description="Order placed for purchasing the pet", example="{petId:456,quantity:100}") Order order + @Body(description="Order placed for purchasing the pet", example="{petId:456,quantity:100}") CreateOrder order ) throws IdConflict, NotAcceptable, UnsupportedMediaType { - return store.add(order); + return store.create(order); } @RestMethod( -- To stop receiving notification emails like this one, please contact jamesbog...@apache.org.