You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/10/08 14:31:14 UTC
[juneau] branch master updated: PetStore updates. Minor bug fixes.
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 205d20f PetStore updates. Minor bug fixes.
205d20f is described below
commit 205d20f8237fe5892256f07cf124d3fe700047cf
Author: JamesBognar <ja...@apache.org>
AuthorDate: Mon Oct 8 10:31:01 2018 -0400
PetStore updates. Minor bug fixes.
---
.../java/org/apache/juneau/internal/DateUtils.java | 12 +
.../org/apache/juneau/internal/StringUtils.java | 2 +-
juneau-examples/juneau-examples-rest/pom.xml | 10 +
.../examples/rest/petstore/ExpiresAfter.java} | 33 +-
.../examples/rest/petstore/InvalidUsername.java | 2 +-
.../juneau/examples/rest/petstore/Order.java | 66 --
.../juneau/examples/rest/petstore/PetCreate.java | 54 -
.../juneau/examples/rest/petstore/PetStore.java | 561 +++++------
.../examples/rest/petstore/PetStoreResource.java | 407 +++-----
.../examples/rest/petstore/PetStoreService.java | 259 +++++
.../rest/petstore/{ => dto}/CreateOrder.java | 58 +-
.../{PetUpdate.java => dto/CreatePet.java} | 78 +-
.../juneau/examples/rest/petstore/dto/Order.java | 138 +++
.../rest/petstore/{ => dto}/OrderStatus.java | 2 +-
.../examples/rest/petstore/{ => dto}/Pet.java | 135 ++-
.../rest/petstore/{ => dto}/PetStatus.java | 2 +-
.../examples/rest/petstore/{ => dto}/PetTag.java | 2 +-
.../examples/rest/petstore/{ => dto}/Species.java | 44 +-
.../examples/rest/petstore/dto/UpdatePet.java | 97 ++
.../examples/rest/petstore/{ => dto}/User.java | 79 +-
.../rest/petstore/{ => dto}/UserStatus.java | 2 +-
.../src/main/resources/META-INF/persistence.xml | 34 +
.../rest/petstore/PetStoreResource_orig.json | 1048 --------------------
.../apache/juneau/examples/rest/petstore/Pets.json | 24 -
.../examples/rest/petstore/{ => init}/Orders.json | 0
.../rest/petstore/{Users.json => init/Pets.json} | 14 +-
.../petstore/{Species.json => init/Users.json} | 9 +-
.../rest/client/remote/RemoteMethodMeta.java | 2 +-
.../apache/juneau/rest/BasicRestCallHandler.java | 2 +
.../java/org/apache/juneau/rest/RestContext.java | 38 +
.../java/org/apache/juneau/rest/RestResponse.java | 10 +-
.../java/org/apache/juneau/rest/RestServlet.java | 21 +-
.../juneau/rest/util/FinishablePrintWriter.java | 5 +-
33 files changed, 1290 insertions(+), 1960 deletions(-)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java
index e052602..36a6da8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DateUtils.java
@@ -125,6 +125,18 @@ public final class DateUtils {
}
/**
+ * Parses an ISO8601 string and converts it to a {@link Date}.
+ *
+ * @param s The string to parse.
+ * @return The parsed value, or <jk>null</jk> if the string was <jk>null</jk> or empty.
+ */
+ public static Date parseISO8601(String s) {
+ if (isEmpty(s))
+ return null;
+ return DatatypeConverter.parseDateTime(toValidISO8601DT(s)).getTime();
+ }
+
+ /**
* Formats the given date according to the RFC 1123 pattern.
*
* @param date The date to format.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
index 1a4f169..1beabc9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -1882,7 +1882,7 @@ public final class StringUtils {
}
/**
- * Same as {@link #urlEncode(String)} except only excapes characters that absolutely need to be escaped.
+ * Same as {@link #urlEncode(String)} except only escapes characters that absolutely need to be escaped.
*
* @param s The string to escape.
* @return The encoded string, or <jk>null</jk> if input is <jk>null</jk>.
diff --git a/juneau-examples/juneau-examples-rest/pom.xml b/juneau-examples/juneau-examples-rest/pom.xml
index a33df7e..a614d52 100644
--- a/juneau-examples/juneau-examples-rest/pom.xml
+++ b/juneau-examples/juneau-examples-rest/pom.xml
@@ -77,6 +77,16 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ <version>5.0.9.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <version>5.0.9.Final</version>
+ </dependency>
</dependencies>
<build>
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Tags.json b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/ExpiresAfter.java
similarity index 73%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Tags.json
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/ExpiresAfter.java
index 1a1caef..d7a2f37 100644
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Tags.json
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/ExpiresAfter.java
@@ -2,7 +2,7 @@
// * 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 *
+// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
@@ -10,13 +10,26 @@
// * "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.petstore;
-[
- {id:101, name:'friendly'},
- {id:102, name:'special'},
- {id:103, name:'intelligent'},
- {id:104, name:'mean'},
- {id:105, name:'easy to care for'},
- {id:106, name:'smells nice'},
- {id:107, name:'loyal'}
-]
+import java.util.*;
+
+import org.apache.juneau.http.annotation.*;
+
+@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;
+ public ExpiresAfter(Date d) {
+ this.c = new GregorianCalendar();
+ c.setTime(d);
+ }
+ public Calendar toCalendar() {
+ return c;
+ }
+}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsername.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsername.java
index a48f0c9..5553ec9 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsername.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsername.java
@@ -26,6 +26,6 @@ public class InvalidUsername extends BadRequest {
* Constructor.
*/
public InvalidUsername() {
- super("Invalid username provided. Must be 8 or more characters or digits.");
+ super("Invalid username provided. Must be between 3 and 8 characters or digits.");
}
}
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
deleted file mode 100644
index 8876e8d..0000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Order.java
+++ /dev/null
@@ -1,66 +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.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,shipDate,status")
-@Example("{id:123,petId:456,shipDate:'2012-12-21',status:'APPROVED'}")
-public class Order {
- private long id, petId;
- private Date shipDate;
- private OrderStatus status;
-
- public long getId() {
- return id;
- }
-
- @Html(link="servlet:/store/order/{id}")
- public Order id(long id) {
- this.id = id;
- return this;
- }
-
- @Html(link="servlet:/pet/{id}")
- public long getPetId() {
- return petId;
- }
-
- public Order petId(long petId) {
- this.petId = petId;
- return this;
- }
-
- @Swap(DateSwap.ISO8601D.class)
- public Date getShipDate() {
- return shipDate;
- }
-
- public Order shipDate(Date 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/PetCreate.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetCreate.java
deleted file mode 100644
index 19428ae..0000000
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetCreate.java
+++ /dev/null
@@ -1,54 +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.petstore;
-
-import org.apache.juneau.annotation.*;
-
-/**
- * Bean for creating {@link Pet} objects.
- */
-public class PetCreate {
-
- private final String name;
- private final float price;
- private final String species;
- private final String[] tags;
-
- @BeanConstructor(properties="name,price,species,tags")
- public PetCreate(String name, float price, String species, String[] tags) {
- this.name = name;
- this.price = price;
- this.species = species;
- this.tags = tags;
- }
-
- public static PetCreate example() {
- return new PetCreate("Doggie", 9.99f, "Dog", new String[] {"friendly","cute"});
- }
-
- public String getName() {
- return name;
- }
-
- public float getPrice() {
- return price;
- }
-
- public String getSpecies() {
- return species;
- }
-
- public String[] getTags() {
- return tags;
- }
-}
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 b9a4208..24c0cfc 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
@@ -12,348 +12,233 @@
// ***************************************************************************************************************************
package org.apache.juneau.examples.rest.petstore;
-import java.io.*;
+import static org.apache.juneau.http.HttpMethodName.*;
+
import java.util.*;
-import java.util.concurrent.*;
import org.apache.juneau.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.transform.*;
-import org.apache.juneau.utils.*;
+import org.apache.juneau.examples.rest.petstore.dto.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.client.remote.*;
+import org.apache.juneau.rest.exception.*;
+import org.apache.juneau.rest.response.*;
/**
- * Pet store database application.
+ * Defines the interface for both the server-side and client-side pet store application.
*/
-public class PetStore {
-
- // Our "databases".
- IdMap<Long,Pet> petDb = IdMap.createLongMap(Pet.class);
- IdMap<Long,Species> speciesDb = IdMap.createLongMap(Species.class);
- IdMap<Long,Order> orderDb = IdMap.createLongMap(Order.class);
- IdMap<Long,PetTag> tagDb = IdMap.createLongMap(PetTag.class);
- ConcurrentHashMap<String,User> userDb = new ConcurrentHashMap<>();
-
- public PetStore init() throws Exception {
-
- // Load our databases from local JSON files.
-
- JsonParser parser = JsonParser.create().build();
-
- // Note that these must be loaded in the specified order to prevent IdNotFound exceptions.
- for (Species s : parser.parse(getStream("Species.json"), Species[].class))
- add(s);
- for (PetTag t : parser.parse(getStream("Tags.json"), PetTag[].class))
- add(t);
-
- parser = parser.builder().pojoSwaps(new CategorySwap(), new TagSwap()).build();
- for (Pet p : parser.parse(getStream("Pets.json"), Pet[].class))
- add(p);
-
- parser = parser.builder().pojoSwaps(new PetSwap()).build();
- for (Order o : parser.parse(getStream("Orders.json"), Order[].class))
- add(o);
-
- for (User u : parser.parse(getStream("Users.json"), User[].class))
- add(u);
-
- return this;
- }
-
- private InputStream getStream(String fileName) {
- return getClass().getResourceAsStream(fileName);
- }
-
- public Pet getPet(long id) throws IdNotFound {
- Pet value = petDb.get(id);
- if (value == null)
- throw new IdNotFound(id, Pet.class);
- return value;
- }
-
- public Species getSpecies(long id) throws IdNotFound {
- Species value = speciesDb.get(id);
- if (value == null)
- throw new IdNotFound(id, Pet.class);
- return value;
- }
-
- public Species getSpecies(String name) throws IdNotFound {
- for (Species value : speciesDb.values())
- if (value.getName().equals(name))
- return value;
- throw new InvalidSpecies();
- }
-
- public Order getOrder(long id) throws IdNotFound {
- Order value = orderDb.get(id);
- if (value == null)
- throw new IdNotFound(id, Pet.class);
- return value;
- }
-
- public PetTag getTag(long id) throws IdNotFound {
- PetTag value = tagDb.get(id);
- if (value == null)
- throw new IdNotFound(id, Pet.class);
- return value;
- }
-
- public PetTag getTag(String name) throws InvalidTag {
- for (PetTag value : tagDb.values())
- if (value.getName().equals(name))
- return value;
- throw new InvalidTag();
- }
-
- public User getUser(String username) throws InvalidUsername, IdNotFound {
- assertValidUsername(username);
- for (User user : userDb.values())
- if (user.getUsername().equals(username))
- return user;
- throw new IdNotFound(username, User.class);
- }
-
- public boolean isValid(String username, String password) {
- for (User user : userDb.values())
- if (user.getUsername().equals(username))
- return user.getPassword().equals(password);
- return false;
- }
-
- public Collection<Pet> getPets() {
- return petDb.values();
- }
-
- public Collection<Species> getCategories() {
- return speciesDb.values();
- }
-
- public Collection<Order> getOrders() {
- return orderDb.values();
- }
-
- public Collection<PetTag> getTags() {
- return tagDb.values();
- }
-
- public Collection<User> getUsers() {
- return userDb.values();
- }
-
- 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);
- return value;
- }
-
- public Species add(Species value) throws IdConflict {
- if (value.getId() == 0)
- value.id(speciesDb.nextId());
- Species old = speciesDb.putIfAbsent(value.getId(), value);
- if (old != null)
- throw new IdConflict(value.getId(), Species.class);
- return value;
- }
-
- public Order add(Order value) throws IdConflict {
- if (value.getId() == 0)
- value.id(orderDb.nextId());
- Order old = orderDb.putIfAbsent(value.getId(), value);
- if (old != null)
- throw new IdConflict(value.getId(), Order.class);
- return value;
- }
-
- public PetTag add(PetTag value) throws IdConflict {
- if (value.getId() == 0)
- value.id(tagDb.nextId());
- PetTag old = tagDb.putIfAbsent(value.getId(), value);
- if (old != null)
- throw new IdConflict(value.getId(), PetTag.class);
- return value;
- }
-
- public User add(User value) throws IdConflict, InvalidUsername {
- assertValidUsername(value.getUsername());
- User old = userDb.putIfAbsent(value.getUsername(), value);
- if (old != null)
- throw new IdConflict(value.getUsername(), User.class);
- return value;
- }
-
- public Pet create(PetCreate pc) {
- Pet p = new Pet();
- p.name(pc.getName());
- p.price(pc.getPrice());
- p.species(getSpecies(pc.getSpecies()));
- p.tags(getTags(pc.getTags()));
- p.status(PetStatus.AVAILABLE);
- return add(p);
- }
-
- public Pet update(PetUpdate pu) throws IdNotFound {
- Pet p = petDb.get(pu.getId());
- if (p == null)
- throw new IdNotFound(pu.getId(), Pet.class);
- p.name(pu.getName());
- p.price(pu.getPrice());
- p.species(getSpecies(pu.getSpecies()));
- p.tags(getTags(pu.getTags()));
- p.status(pu.getStatus());
- return p;
- }
-
- public Pet update(Pet pet) {
- petDb.put(pet.getId(), pet);
- return pet;
- }
-
- public Order create(CreateOrder c) {
- Order o = new Order();
- o.petId(c.getPetId());
- o.shipDate(c.getShipDate());
- o.status(OrderStatus.PLACED);
- return add(o);
- }
-
- private PetTag[] getTags(String[] tags) {
- if (tags == null)
- return null;
- PetTag[] l = new PetTag[tags.length];
- for (int i = 0; i < tags.length; i++)
- l[i]= getOrCreateTag(tags[i]);
- return l;
- }
-
- private PetTag getOrCreateTag(String name) {
- for (PetTag t : tagDb.values())
- if (t.getName().equals(name))
- return t;
- return add(new PetTag().name(name));
- }
-
- public Order update(Order value) throws IdNotFound {
- Order old = orderDb.replace(value.getId(), value);
- if (old == null)
- throw new IdNotFound(value.getId(), Order.class);
- return value;
- }
-
- public PetTag update(PetTag value) throws IdNotFound, InvalidTag {
- assertValidTag(value.getName());
- PetTag old = tagDb.replace(value.getId(), value);
- if (old == null)
- throw new IdNotFound(value.getId(), PetTag.class);
- return value;
- }
-
- public User update(User value) throws IdNotFound, InvalidUsername {
- assertValidUsername(value.getUsername());
- User old = userDb.replace(value.getUsername(), value);
- if (old == null)
- throw new IdNotFound(value.getUsername(), User.class);
- return value;
- }
-
- public void removePet(long id) throws IdNotFound {
- petDb.remove(getPet(id).getId());
- }
-
- public void removeCategory(long id) throws IdNotFound {
- speciesDb.remove(getSpecies(id).getId());
- }
-
- public void removeOrder(long id) throws IdNotFound {
- orderDb.remove(getOrder(id).getId());
- }
-
- public void removeTag(long id) throws IdNotFound {
- tagDb.remove(getTag(id).getId());
- }
-
- public void removeUser(String username) throws IdNotFound {
- userDb.remove(getUser(username).getUsername());
- }
-
- private void assertValidUsername(String username) throws InvalidUsername {
- if (username == null || ! username.matches("[\\w\\d]{8,}"))
- throw new InvalidUsername();
- }
-
- private void assertValidTag(String tag) throws InvalidTag {
- if (tag == null || ! tag.matches("[\\w\\d]{1,8}"))
- throw new InvalidTag();
- }
-
- public Collection<Pet> getPetsByStatus(PetStatus[] status) {
- List<Pet> list = new ArrayList<>();
- for (Pet p : petDb.values())
- if (p.hasStatus(status))
- list.add(p);
- return list;
- }
-
- public Collection<Pet> getPetsByTags(String[] tags) throws InvalidTag {
- for (String tag : tags)
- assertValidTag(tag);
- List<Pet> list = new ArrayList<>();
- for (Pet p : petDb.values())
- if (p.hasTag(tags))
- list.add(p);
- return list;
- }
-
- public Map<PetStatus,Integer> getInventory() {
- Map<PetStatus,Integer> m = new LinkedHashMap<>();
- for (Pet p : petDb.values()) {
- PetStatus ps = p.getStatus();
- if (! m.containsKey(ps))
- m.put(ps, 1);
- else
- m.put(ps, m.get(ps) + 1);
- }
- return m;
- }
-
- //-----------------------------------------------------------------------------------------------------------------
- // Helper beans
- //-----------------------------------------------------------------------------------------------------------------
-
- public class CategorySwap extends PojoSwap<Species,String> {
- @Override
- public String swap(BeanSession bs, Species o) throws Exception {
- return o.getName();
- }
- @Override
- public Species unswap(BeanSession bs, String o, ClassMeta<?> hint) throws Exception {
- return getSpecies(o);
- }
- }
-
- public class TagSwap extends PojoSwap<PetTag,String> {
- @Override
- public String swap(BeanSession bs, PetTag o) throws Exception {
- return o.getName();
- }
- @Override
- public PetTag unswap(BeanSession bs, String o, ClassMeta<?> hint) throws Exception {
- return getTag(o);
- }
- }
-
- public class PetSwap extends PojoSwap<Pet,Long> {
- @Override
- public Long swap(BeanSession bs, Pet o) throws Exception {
- return o.getId();
- }
- @Override
- public Pet unswap(BeanSession bs, Long o, ClassMeta<?> hint) throws Exception {
- return petDb.get(o);
- }
- }
+@RemoteResource(path="/petstore")
+public interface PetStore {
+
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ // Pets
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ @RemoteMethod(method=GET, path="/pet")
+ public Collection<Pet> getPets() throws NotAcceptable;
+
+ @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;
+
+ @RemoteMethod /* method and path inferred from method name */
+ public long postPet(
+ @Body(
+ description="Pet object to add to the store"
+ ) CreatePet pet
+ ) throws IdConflict, NotAcceptable, UnsupportedMediaType;
+
+ @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;
+
+ @RemoteMethod(method=GET, path="/pet/findByStatus")
+ public Collection<Pet> 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;
+
+ @RemoteMethod(method=GET, path="/pet/findByTags")
+ @Deprecated
+ public Collection<Pet> findPetsByTags(
+ @Query(
+ name="tags",
+ description="Tags to filter by",
+ required=true,
+ example="['tag1','tag2']"
+ )
+ String[] tags
+ ) throws InvalidTag, NotAcceptable;
+
+ @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
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ @RemoteMethod(method=GET, path="/store/order")
+ public Collection<Order> getOrders() throws NotAcceptable;
+
+ @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;
+
+ @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;
+
+ @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;
+
+ @RemoteMethod(method=GET, path="/store/inventory")
+ public Map<PetStatus,Integer> getStoreInventory() throws NotAcceptable;
+
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ // Users
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ @RemoteMethod(method=GET, path="/user")
+ public Collection<User> getUsers() throws NotAcceptable;
+
+ @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;
+
+ @RemoteMethod
+ public Ok postUser(
+ @Body(
+ description="Created user object"
+ )
+ User user
+ ) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType;
+
+ @RemoteMethod(method=POST, path="/user/createWithArray")
+ public Ok createUsers(
+ @Body(
+ description="List of user objects"
+ )
+ User[] users
+ ) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType;
+
+ @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;
+
+ @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;
+
+ @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<Integer> rateLimit,
+ Value<ExpiresAfter> expiresAfter,
+ RestRequest req,
+ RestResponse res
+ ) throws InvalidLogin, NotAcceptable;
+
+ @RemoteMethod(method=GET, path="/user/logout")
+ public Ok logout() throws NotAcceptable;
}
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 f612025..42bde51 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
@@ -23,9 +23,9 @@ import java.util.Map;
import org.apache.juneau.*;
import org.apache.juneau.dto.html5.*;
+import org.apache.juneau.examples.rest.petstore.dto.*;
import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.http.annotation.Body;
-import org.apache.juneau.http.annotation.Header;
+import org.apache.juneau.internal.*;
import org.apache.juneau.jsonschema.annotation.*;
import org.apache.juneau.microservice.*;
import org.apache.juneau.rest.*;
@@ -55,6 +55,7 @@ import org.apache.juneau.rest.converters.*;
navlinks={
"up: request:/..",
"options: servlet:/?method=OPTIONS",
+ "init: servlet:/init",
"$W{ContentTypeMenuItem}",
"$W{ThemeMenuItem}",
"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/petstore/$R{servletClassSimple}.java"
@@ -122,14 +123,14 @@ import org.apache.juneau.rest.converters.*;
),
staticFiles={"htdocs:htdocs"}
)
-public class PetStoreResource extends BasicRestServletJena {
+public class PetStoreResource extends BasicRestServletJena implements PetStore {
private static final long serialVersionUID = 1L;
- private PetStore store;
+ private PetStoreService store;
@RestHook(INIT)
- public void initDatabase(RestContextBuilder builder) throws Exception {
- store = new PetStore().init();
+ public void startup(RestContextBuilder builder) throws Exception {
+ store = new PetStoreService();
}
@RestMethod(
@@ -146,9 +147,52 @@ public class PetStoreResource extends BasicRestServletJena {
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ // Initialization
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ @RestMethod(
+ summary="Initialize database form entry page"
+ )
+ public Div getInit() {
+ return div(
+ form("servlet:/init").method(POST).target("buf").children(
+ table(
+ tr(
+ th("Initialize petstore database:"),
+ td(input("radio").name("init-method").value("direct").checked(true), "direct", input("radio").name("init-method").value("rest"), "rest"),
+ td(button("submit", "Submit").style("float:right").onclick("scrolling=true"))
+ )
+ )
+ ),
+ br(),
+ iframe().id("buf").name("buf").style("width:800px;height:600px;").onload("window.parent.scrolling=false;"),
+ script("text/javascript",
+ "var scrolling = false;",
+ "function scroll() { if (scrolling) { document.getElementById('buf').contentWindow.scrollBy(0,50); } setTimeout('scroll()',200); } ",
+ "scroll();"
+ )
+ );
+ }
+
+ @RestMethod(
+ summary="Initialize database"
+ )
+ public void postInit(
+ @FormData("init-method") String initMethod,
+ RestResponse res
+ ) throws Exception {
+ res.setHeader("Content-Encoding", "identity");
+ if ("direct".equals(initMethod))
+ store.initDirect(res.getDirectWriter("text/plain"));
+ else
+ store.initViaRest(res.getDirectWriter("text/plain"));
+ }
+
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Pets
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ @Override /* PetStore */
@RestMethod(
name=GET,
path="/pet",
@@ -177,6 +221,7 @@ public class PetStoreResource extends BasicRestServletJena {
return store.getPets();
}
+ @Override /* PetStore */
@RestMethod(
name=GET,
path="/pet/{petId}",
@@ -189,18 +234,11 @@ public class PetStoreResource extends BasicRestServletJena {
}
)
)
- public Pet getPet(
- @Path(
- name="petId",
- description="ID of pet to return",
- example="123"
- )
- long petId
- ) throws IdNotFound, NotAcceptable {
-
+ public Pet getPet(long petId) throws IdNotFound, NotAcceptable {
return store.getPet(petId);
}
+ @Override /* PetStore */
@RestMethod(
summary="Add a new pet to the store",
swagger=@MethodSwagger(
@@ -210,14 +248,11 @@ public class PetStoreResource extends BasicRestServletJena {
}
)
)
- public Ok postPet(
- @Body(description="Pet object to add to the store") PetCreate pet
- ) throws IdConflict, NotAcceptable, UnsupportedMediaType {
-
- store.create(pet);
- return OK;
+ public long postPet(CreatePet pet) throws IdConflict, NotAcceptable, UnsupportedMediaType {
+ return store.create(pet).getId();
}
+ @Override /* PetStore */
@RestMethod(
name=PUT,
path="/pet/{petId}",
@@ -229,14 +264,67 @@ public class PetStoreResource extends BasicRestServletJena {
}
)
)
- public Ok updatePet(
- @Body(description="Pet object that needs to be added to the store") PetUpdate pet
- ) throws IdNotFound, NotAcceptable, UnsupportedMediaType {
-
+ 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<Pet> 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<Pet> 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;
+ }
+
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ // Pets - extra methods
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
@RestMethod(
name=GET,
path="/pet/{petId}/edit",
@@ -288,7 +376,7 @@ public class PetStoreResource extends BasicRestServletJena {
),
tr(
th("Tags:"),
- td(input().name("tags").type("text").value(PetTag.asString(pet.getTags()))),
+ td(input().name("tags").type("text").value(StringUtils.join(pet.getTags(), ','))),
td(new Tooltip("❓", "Arbitrary textual tags (comma-delimited).", br(), "e.g. 'fluffy,friendly'"))
),
tr(
@@ -312,131 +400,6 @@ public class PetStoreResource extends BasicRestServletJena {
);
}
- @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<Pet> 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 {
-
- return store.getPetsByStatus(status);
- }
-
- @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<Pet> findPetsByTags(
- @Query(
- name="tags",
- description="Tags to filter by",
- required=true,
- example="['tag1','tag2']"
- )
- String[] tags
- ) throws InvalidTag, NotAcceptable {
-
- return store.getPetsByTags(tags);
- }
-
- @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(
- @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 {
-
- store.removePet(petId);
- return OK;
- }
-
- @RestMethod(
- name=POST,
- path="/pet/{petId}/uploadImage",
- summary="Uploads an image",
- swagger=@MethodSwagger(
- tags="pet",
- value={
- "security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"
- }
- )
- )
- public Ok uploadImage(
- @Path(
- name="petId",
- description="ID of pet to update",
- example="123"
- )
- long petId,
- @FormData(
- name="additionalMetadata",
- description="Additional data to pass to server",
- example="Foobar"
- )
- String additionalMetadata,
- @FormData(
- name="file",
- description="file to upload",
- required=true,
- type="file"
- )
- byte[] file
- ) throws NotAcceptable, UnsupportedMediaType {
-
- return OK;
- }
-
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Orders
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -454,6 +417,7 @@ public class PetStoreResource extends BasicRestServletJena {
;
}
+ @Override
@RestMethod(
name=GET,
path="/store/order",
@@ -477,6 +441,7 @@ public class PetStoreResource extends BasicRestServletJena {
return store.getOrders();
}
+ @Override
@RestMethod(
name=GET,
path="/store/order/{orderId}",
@@ -486,22 +451,13 @@ public class PetStoreResource extends BasicRestServletJena {
tags="store"
)
)
- public Order getOrder(
- @Path(
- name="orderId",
- description="ID of order to fetch",
- maximum="1000",
- minimum="101",
- example="123"
- )
- long orderId
- ) throws InvalidId, IdNotFound, NotAcceptable {
-
- if (orderId < 101 || orderId > 1000)
+ 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",
@@ -513,23 +469,12 @@ public class PetStoreResource extends BasicRestServletJena {
DateSwap.ISO8601D.class
}
)
- public Order placeOrder(
- @FormData(
- name="petId",
- description="Pet ID"
- )
- long petId,
- @FormData(
- name="shipDate",
- description="Ship date"
- )
- Date shipDate
- ) throws IdConflict, NotAcceptable, UnsupportedMediaType {
-
- CreateOrder co = new CreateOrder(petId, shipDate);
- return store.create(co);
+ 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}",
@@ -542,22 +487,14 @@ public class PetStoreResource extends BasicRestServletJena {
tags="store"
)
)
- public Ok deletePurchaseOrder(
- @Path(
- name="orderId",
- description="ID of the order that needs to be deleted",
- minimum="1",
- example="5"
- )
- long orderId
- ) throws InvalidId, IdNotFound, NotAcceptable {
-
+ 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",
@@ -581,6 +518,7 @@ public class PetStoreResource extends BasicRestServletJena {
// Users
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ @Override
@RestMethod(
name=GET,
path="/user",
@@ -594,6 +532,7 @@ public class PetStoreResource extends BasicRestServletJena {
return store.getUsers();
}
+ @Override
@RestMethod(
name=GET,
path="/user/{username}",
@@ -602,17 +541,11 @@ public class PetStoreResource extends BasicRestServletJena {
tags="user"
)
)
- public User getUser(
- @Path(
- name="username",
- description="The name that needs to be fetched. Use user1 for testing."
- )
- String username
- ) throws InvalidUsername, IdNotFound, NotAcceptable {
-
+ public User getUser(String username) throws InvalidUsername, IdNotFound, NotAcceptable {
return store.getUser(username);
}
+ @Override
@RestMethod(
summary="Create user",
description="This can only be done by the logged in user.",
@@ -620,14 +553,12 @@ public class PetStoreResource extends BasicRestServletJena {
tags="user"
)
)
- public Ok postUser(
- @Body(description="Created user object") User user
- ) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType {
-
- store.add(user);
+ public Ok postUser(User user) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType {
+ store.create(user);
return OK;
}
+ @Override
@RestMethod(
name=POST,
path="/user/createWithArray",
@@ -636,15 +567,13 @@ public class PetStoreResource extends BasicRestServletJena {
tags="user"
)
)
- public Ok createUsers(
- @Body(description="List of user objects") User[] users
- ) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType {
-
+ public Ok createUsers(User[] users) throws InvalidUsername, IdConflict, NotAcceptable, UnsupportedMediaType {
for (User user : users)
- store.add(user);
+ store.create(user);
return OK;
}
+ @Override
@RestMethod(
name=PUT,
path="/user/{username}",
@@ -654,22 +583,12 @@ public class PetStoreResource extends BasicRestServletJena {
tags="user"
)
)
- 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 {
-
+ public Ok updateUser(String username, User user) throws InvalidUsername, IdNotFound, NotAcceptable, UnsupportedMediaType {
store.update(user);
return OK;
}
+ @Override
@RestMethod(
name=DELETE,
path="/user/{username}",
@@ -679,18 +598,12 @@ public class PetStoreResource extends BasicRestServletJena {
tags="user"
)
)
- public Ok deleteUser(
- @Path(
- name="username",
- description="The name that needs to be deleted"
- )
- String username
- ) throws InvalidUsername, IdNotFound, NotAcceptable {
-
+ public Ok deleteUser(String username) throws InvalidUsername, IdNotFound, NotAcceptable {
store.removeUser(username);
return OK;
}
+ @Override
@RestMethod(
name=GET,
path="/user/login",
@@ -700,27 +613,8 @@ public class PetStoreResource extends BasicRestServletJena {
)
)
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<Integer> rateLimit,
Value<ExpiresAfter> expiresAfter,
RestRequest req,
@@ -737,24 +631,7 @@ public class PetStoreResource extends BasicRestServletJena {
return OK;
}
- @ResponseHeader(
- name="X-Expires-After",
- type="string",
- format="date-time",
- description="Date in UTC when token expires",
- example="2012-10-21"
- )
- public static class ExpiresAfter {
- private final Calendar c;
- public ExpiresAfter(Date d) {
- this.c = new GregorianCalendar();
- c.setTime(d);
- }
- public Calendar toCalendar() {
- return c;
- }
- }
-
+ @Override
@RestMethod(
name=GET,
path="/user/logout",
@@ -763,8 +640,8 @@ public class PetStoreResource extends BasicRestServletJena {
tags="user"
)
)
- public Ok logout(RestRequest req) throws NotAcceptable {
- req.getSession().removeAttribute("login-expires");
+ public Ok logout() throws NotAcceptable {
+ getRequest().getSession().removeAttribute("login-expires");
return OK;
}
}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreService.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreService.java
new file mode 100644
index 0000000..817271d
--- /dev/null
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreService.java
@@ -0,0 +1,259 @@
+// ***************************************************************************************************************************
+// * 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.petstore;
+
+import static java.text.MessageFormat.*;
+
+import java.io.*;
+import java.util.*;
+
+import javax.persistence.*;
+
+import org.apache.juneau.examples.rest.petstore.dto.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.rest.client.*;
+
+/**
+ * Pet store database application.
+ */
+public class PetStoreService {
+
+ private final EntityManagerFactory entityManagerFactory;
+
+ public PetStoreService() {
+ entityManagerFactory = Persistence.createEntityManagerFactory("test");
+ }
+
+ public PetStoreService initDirect(PrintWriter w) throws Exception {
+
+ EntityManager em = getEntityManager();
+ EntityTransaction et = em.getTransaction();
+ JsonParser parser = JsonParser.create().build();
+
+ et.begin();
+
+ for (Pet x : em.createQuery("select X from Pet 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;
+ }
+
+ public PetStoreService initViaRest(PrintWriter w) throws Exception {
+ JsonParser parser = JsonParser.create().ignoreUnknownBeanProperties().build();
+
+ try (RestClient rc = RestClient.create().json().rootUrl("http://localhost:10000").build()) {
+ PetStore ps = rc.getRemoteResource(PetStore.class);
+
+ 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 : parser.parse(getStream("init/Pets.json"), CreatePet[].class)) {
+ long id = ps.postPet(x);
+ w.println(format("Created pet: id={0}, name={1}", id, x.getName()));
+ }
+ for (Order x : parser.parse(getStream("init/Orders.json"), Order[].class)) {
+ long id = ps.placeOrder(x.getPetId(), x.getUsername());
+ w.println(format("Created order: id={0}", id));
+ }
+ for (User x: parser.parse(getStream("init/Users.json"), User[].class)) {
+ ps.postUser(x);
+ w.println(format("Created user: username={0}", x.getUsername()));
+ }
+ }
+
+ return this;
+ }
+
+
+ public Pet getPet(long id) throws IdNotFound {
+ return find(Pet.class, id);
+ }
+
+ public Order getOrder(long id) throws IdNotFound {
+ return find(Order.class, id);
+ }
+
+ public User getUser(String username) throws InvalidUsername, IdNotFound {
+ assertValidUsername(username);
+ return find(User.class, username);
+ }
+
+ public List<Pet> getPets() {
+ return query("select X from Pet X", Pet.class);
+ }
+
+ public List<Order> getOrders() {
+ return query("select X from PetstoreOrder X", Order.class);
+ }
+
+ public List<User> getUsers() {
+ return query("select X from PetstoreUser X", User.class);
+ }
+
+ public Pet create(CreatePet c) {
+ return merge(new Pet().status(PetStatus.AVAILABLE).apply(c));
+ }
+
+ public Order create(CreateOrder c) {
+ return merge(new Order().status(OrderStatus.PLACED).apply(c));
+ }
+
+ public User create(User c) {
+ return merge(new User().apply(c));
+ }
+
+ public Pet update(UpdatePet u) throws IdNotFound {
+ return merge(getPet(u.getId()).apply(u));
+ }
+
+ public Order update(Order o) throws IdNotFound {
+ return merge(getOrder(o.getId()).apply(o));
+ }
+
+ public User update(User u) throws IdNotFound, InvalidUsername {
+ assertValidUsername(u.getUsername());
+ return merge(getUser(u.getUsername()).apply(u));
+ }
+
+ public void removePet(long id) throws IdNotFound {
+ remove(getPet(id));
+ }
+
+ public void removeOrder(long id) throws IdNotFound {
+ remove(getOrder(id));
+ }
+
+ public void removeUser(String username) throws IdNotFound {
+ remove(getUser(username));
+ }
+
+ public Collection<Pet> getPetsByStatus(PetStatus[] status) {
+ return getEntityManager()
+ .createQuery("select X from Pet X where X.status in :status", Pet.class)
+ .setParameter("status", status)
+ .getResultList();
+ }
+
+ public Collection<Pet> getPetsByTags(String[] tags) throws InvalidTag {
+ return getEntityManager()
+ .createQuery("select X from Pet X where X.tags in :tags", Pet.class)
+ .setParameter("tags", tags)
+ .getResultList();
+ }
+
+ public Map<PetStatus,Integer> getInventory() {
+ Map<PetStatus,Integer> 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;
+ }
+
+ 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 EntityManager getEntityManager() {
+ return entityManagerFactory.createEntityManager();
+ }
+
+ private <T> T merge(T t) {
+ EntityManager em = getEntityManager();
+ try {
+ EntityTransaction et = em.getTransaction();
+ et.begin();
+ t = em.merge(t);
+ et.commit();
+ return t;
+ } finally {
+ em.close();
+ }
+ }
+
+ private <T> void remove(T t) {
+ EntityManager em = getEntityManager();
+ try {
+ EntityTransaction et = em.getTransaction();
+ et.begin();
+ em.remove(t);
+ et.commit();
+ } finally {
+ em.close();
+ }
+ }
+
+ private <T> List<T> query(String query, Class<T> t) {
+ return getEntityManager().createQuery(query, t).getResultList();
+ }
+
+ private <T> T find(Class<T> t, Object id) throws IdNotFound {
+ T o = getEntityManager().find(t, id);
+ if (o == null)
+ throw new IdNotFound(id, t);
+ return o;
+ }
+
+ private InputStream getStream(String fileName) {
+ return getClass().getResourceAsStream(fileName);
+ }
+}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/CreateOrder.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/CreateOrder.java
similarity index 57%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/CreateOrder.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/CreateOrder.java
index 23f4ab9..2b42888 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/CreateOrder.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/CreateOrder.java
@@ -10,35 +10,65 @@
// * "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.petstore;
-
-import java.util.*;
+package org.apache.juneau.examples.rest.petstore.dto;
import org.apache.juneau.annotation.*;
-import org.apache.juneau.internal.*;
/**
* Bean for creating {@link Order} objects.
+ * Also serves as the superclass for the {@link Order} object.
*/
+@Bean(fluentSetters=true, properties="petId,username")
public class CreateOrder {
- private final long petId;
- private final Date shipDate;
- @BeanConstructor(properties="petId,shipDate")
- public CreateOrder(long petId, Date shipDate) {
+ private long petId;
+ private String username;
+
+ /**
+ * Optional constructor.
+ */
+ @BeanConstructor(properties="petId,username")
+ public CreateOrder(long petId, String username) {
this.petId = petId;
- this.shipDate = shipDate;
+ this.username = username;
}
- public static CreateOrder example() {
- return new CreateOrder(123, StringUtils.parseIsoDate("2012-12-21"));
- }
+ /**
+ * Constructor needed by JPA.
+ */
+ public CreateOrder() {}
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // Bean properties
+ //-----------------------------------------------------------------------------------------------------------------
public long getPetId() {
return petId;
}
- public Date getShipDate() {
- return shipDate;
+ public CreateOrder petId(long value) {
+ this.petId = value;
+ return this;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public CreateOrder username(String value) {
+ this.username = value;
+ return this;
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // Other
+ //-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Used to populate Swagger examples.
+ * Example is inferred from the method name.
+ */
+ public static CreateOrder example() {
+ return new CreateOrder(123, "sampleuser");
}
}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetUpdate.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/CreatePet.java
similarity index 53%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetUpdate.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/CreatePet.java
index c406359..1cd665c 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetUpdate.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/CreatePet.java
@@ -10,57 +10,89 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.petstore.dto;
import org.apache.juneau.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
/**
* Bean for creating {@link Pet} objects.
*/
-public class PetUpdate {
-
- private final long id;
- private final String name;
- private final float price;
- private final String species;
- private final String[] tags;
- private final PetStatus status;
-
- @BeanConstructor(properties="id,name,price,species,tags,status")
- public PetUpdate(long id, String name, float price, String species, String[] tags, PetStatus status) {
- this.id = id;
+@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.
+ */
+ public CreatePet(String name, float price, Species species, String[] tags) {
this.name = name;
this.price = price;
this.species = species;
this.tags = tags;
- this.status = status;
}
- public static PetUpdate example() {
- return new PetUpdate(123l, "Doggie", 9.99f, "doc", new String[] {"friendly","cute"}, PetStatus.AVAILABLE);
- }
+ /**
+ * Empty constructor.
+ */
+ public CreatePet() {}
- public long getId() {
- return id;
- }
+ //-----------------------------------------------------------------------------------------------------------------
+ // Bean properties
+ //-----------------------------------------------------------------------------------------------------------------
public String getName() {
return name;
}
+ public CreatePet name(String value) {
+ this.name = value;
+ return this;
+ }
+
public float getPrice() {
return price;
}
- public String getSpecies() {
+ public CreatePet price(float value) {
+ this.price = value;
+ return this;
+ }
+
+ public Species getSpecies() {
return species;
}
+ public CreatePet species(Species value) {
+ this.species = value;
+ return this;
+ }
+
public String[] getTags() {
return tags;
}
- public PetStatus getStatus() {
- return status;
+ public CreatePet tags(String...value) {
+ this.tags = value;
+ return this;
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // Other
+ //-----------------------------------------------------------------------------------------------------------------
+
+ public static CreatePet example() {
+ return new CreatePet("Doggie", 9.99f, Species.DOG, new String[]{"smart","friendly"});
}
}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Order.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Order.java
new file mode 100644
index 0000000..c977b36
--- /dev/null
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Order.java
@@ -0,0 +1,138 @@
+// ***************************************************************************************************************************
+// * 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.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.*;
+
+@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(DateSwap.ISO8601D.class)
+ private Date shipDate;
+
+ public Order apply(CreateOrder o) {
+ this.petId = o.getPetId();
+ this.username = o.getUsername();
+ return this;
+ }
+
+ 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
+ //-----------------------------------------------------------------------------------------------------------------
+
+ public long getId() {
+ return id;
+ }
+
+ public Order id(long id) {
+ this.id = id;
+ return this;
+ }
+
+ public Date getShipDate() {
+ return shipDate;
+ }
+
+ public Order shipDate(Date value) {
+ this.shipDate = value;
+ return this;
+ }
+
+ public OrderStatus getStatus() {
+ return status;
+ }
+
+ public Order status(OrderStatus value) {
+ this.status = value;
+ return this;
+ }
+
+ public long getPetId() {
+ return petId;
+ }
+
+ public Order petId(long value) {
+ this.petId = value;;
+ return this;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public Order username(String value) {
+ this.username = value;
+ return this;
+ }
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // Other
+ //-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * This shows an example generated from a static method.
+ */
+ @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-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/OrderStatus.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/OrderStatus.java
similarity index 97%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/OrderStatus.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/OrderStatus.java
index 5299c69..8eec9f5 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/OrderStatus.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/OrderStatus.java
@@ -10,7 +10,7 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.petstore.dto;
import org.apache.juneau.html.*;
import org.apache.juneau.html.annotation.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Pet.java
similarity index 58%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Pet.java
index e0c3a67..ffb4fb0 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Pet.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Pet.java
@@ -10,39 +10,75 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.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.xml.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.serializer.*;
/**
* Pet bean.
*/
-@Bean(typeName="Pet", fluentSetters=true, properties="id,species,name,photoUrls,tags,price,status")
+@Bean(typeName="Pet", fluentSetters=true, properties="id,species,name,tags,price,status")
+@Entity
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;
- private String name;
- private List<String> photoUrls;
- private List<PetTag> tags;
+
+ @ElementCollection @OrderColumn
+ @Schema(description="Pet attributes.", example="friendly,smart")
+ private List<String> tags;
+
+ @Column @Enumerated(STRING)
+ @Schema(description="Pet species.")
private PetStatus status;
- // This shows an example generated from a static method.
- @Example
- public static Pet example() {
- return new Pet()
- .id(123)
- .species(Species.example())
- .name("Doggie")
- .tags(PetTag.example())
- .status(PetStatus.AVAILABLE);
+ 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;
}
- @Html(link="servlet:/pet/{id}")
+ 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
+ //-----------------------------------------------------------------------------------------------------------------
+
public long getId() {
return id;
}
@@ -52,45 +88,43 @@ public class Pet {
return this;
}
- public Species getSpecies() {
- return species;
+ public String getName() {
+ return name;
}
- public Pet species(Species species) {
- this.species = species;
+ public Pet name(String name) {
+ this.name = name;
return this;
}
- public String getName() {
- return name;
+ public float getPrice() {
+ return price;
}
- public Pet name(String name) {
- this.name = name;
+ public Pet price(float price) {
+ this.price = price;
return this;
}
- @URI
- @Xml(childName="photoUrl")
- public List<String> getPhotoUrls() {
- return photoUrls;
+ public Species getSpecies() {
+ return species;
}
- public Pet photoUrls(List<String> photoUrls) {
- this.photoUrls = photoUrls;
+ public Pet species(Species species) {
+ this.species = species;
return this;
}
- public List<PetTag> getTags() {
+ public List<String> getTags() {
return tags;
}
- public Pet tags(List<PetTag> tags) {
+ public Pet tags(List<String> tags) {
this.tags = tags;
return this;
}
- public Pet tags(PetTag...tags) {
+ public Pet tags(String...tags) {
this.tags = Arrays.asList(tags);
return this;
}
@@ -113,23 +147,38 @@ public class Pet {
public boolean hasTag(String...tags) {
for (String tag : tags)
- for (PetTag t : this.tags)
- if (t.getName().equals(tag))
+ for (String t : this.tags)
+ if (t.equals(tag))
return true;
return false;
}
- @BeanProperty(format="$%.2f") // Renders price in dollars.
- public float getPrice() {
- return price;
+ public java.net.URI getEdit() {
+ return java.net.URI.create("servlet:/pet/edit/{id}");
}
- public Pet price(float price) {
- this.price = price;
- return this;
+ //-----------------------------------------------------------------------------------------------------------------
+ // Other
+ //-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * This shows an example generated from a static method.
+ */
+ @Example
+ public static Pet example() {
+ return new Pet()
+ .id(123)
+ .species(Species.DOG)
+ .name("Doggie")
+ .tags("friendly","smart")
+ .status(PetStatus.AVAILABLE);
}
- public java.net.URI getEdit() {
- return java.net.URI.create("servlet:/pet/edit/{id}");
+
+ public static final class PriceRender extends HtmlRender<Float> {
+ @Override
+ public Object getContent(SerializerSession session, Float value) {
+ return value == null ? null : String.format("$%.2f", value);
+ }
}
}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStatus.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/PetStatus.java
similarity index 97%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStatus.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/PetStatus.java
index 241f80a..8e67d5d 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStatus.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/PetStatus.java
@@ -10,7 +10,7 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.petstore.dto;
import org.apache.juneau.html.*;
import org.apache.juneau.html.annotation.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetTag.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/PetTag.java
similarity index 98%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetTag.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/PetTag.java
index 1257f3d..f968e74 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetTag.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/PetTag.java
@@ -10,7 +10,7 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.petstore.dto;
import java.util.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Species.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Species.java
similarity index 71%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Species.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Species.java
index f9b41c9..0acb1cb 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/Species.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/Species.java
@@ -10,58 +10,26 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.petstore.dto;
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.dto.html5.Img;
+import org.apache.juneau.dto.html5.*;
import org.apache.juneau.html.*;
-import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.html.annotation.Html;
import org.apache.juneau.serializer.*;
-@Bean(typeName="Species", fluentSetters=true)
@Html(render=Species.SpeciesRender.class)
-public class Species {
- private long id;
- private String name;
+public enum Species {
- public long getId() {
- return id;
- }
-
- public Species id(long id) {
- this.id = id;
- return this;
- }
-
- public String getName() {
- return name;
- }
-
- public Species name(String name) {
- this.name = name;
- return this;
- }
-
- @Example
- public static Species example() {
- return new Species()
- .id(123)
- .name("Dog");
- }
+ BIRD, CAT, DOG, FISH, MOUSE, RABBIT, SNAKE;
public static class SpeciesRender extends HtmlRender<Species> {
@Override
public Object getContent(SerializerSession session, Species value) {
- return new Img().src("servlet:/htdocs/"+value.getName().toLowerCase()+".png");
+ return new Img().src("servlet:/htdocs/"+value.name().toLowerCase()+".png");
}
@Override
public String getStyle(SerializerSession session, Species value) {
return "background-color:#FDF2E9";
}
}
-
- @Override /* Object */
- public String toString() {
- return name;
- }
}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/UpdatePet.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/UpdatePet.java
new file mode 100644
index 0000000..bfde4f1
--- /dev/null
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/UpdatePet.java
@@ -0,0 +1,97 @@
+// ***************************************************************************************************************************
+// * 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.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.
+ */
+ 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
+ //-----------------------------------------------------------------------------------------------------------------
+
+ public long getId() {
+ return id;
+ }
+
+ public UpdatePet id(long value) {
+ this.id = value;
+ return this;
+ }
+
+ public PetStatus getStatus() {
+ return status;
+ }
+
+ 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-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/User.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/User.java
similarity index 62%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/User.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/User.java
index 512fdf9..6610ce8 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/User.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/User.java
@@ -10,27 +10,65 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.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.*;
@Bean(typeName="User", fluentSetters=true, properties="username,firstName,lastName,email,password,phone,userStatus")
+@Entity(name="PetstoreUser")
public class User {
- private String username, firstName, lastName, email, password, phone;
+
+ @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;
- // This shows an example provided as a static field.
- @Example
- public static User EXAMPLE = new User()
- .username("billy")
- .firstName("Billy")
- .lastName("Bob")
- .email("billy@apache.org")
- .userStatus(UserStatus.ACTIVE)
- .phone("111-222-3333");
+ 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
+ //-----------------------------------------------------------------------------------------------------------------
- @Html(link="servlet:/user/{username}")
public String getUsername() {
return username;
}
@@ -93,4 +131,21 @@ public class User {
this.userStatus = userStatus;
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-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/UserStatus.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/UserStatus.java
similarity index 97%
rename from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/UserStatus.java
rename to juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/UserStatus.java
index cb5aa50..5fd004f 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/UserStatus.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/dto/UserStatus.java
@@ -10,7 +10,7 @@
// * "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.petstore;
+package org.apache.juneau.examples.rest.petstore.dto;
import org.apache.juneau.html.*;
import org.apache.juneau.html.annotation.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/META-INF/persistence.xml b/juneau-examples/juneau-examples-rest/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..7e1213e
--- /dev/null
+++ b/juneau-examples/juneau-examples-rest/src/main/resources/META-INF/persistence.xml
@@ -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. *
+ ***************************************************************************************************************************
+-->
+<persistence
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
+ version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
+ <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
+ <class>org.apache.juneau.examples.rest.petstore.dto.Pet</class>
+ <class>org.apache.juneau.examples.rest.petstore.dto.Order</class>
+ <class>org.apache.juneau.examples.rest.petstore.dto.User</class>
+ <properties>
+ <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
+ <property name="javax.persistence.jdbc.url" value="jdbc:derby:target/derby/testDB;create=true" />
+ <property name="javax.persistence.jdbc.user" value="" />
+ <property name="javax.persistence.jdbc.password" value="" />
+ <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
+ <property name="hibernate.hbm2ddl.auto" value="create-drop" />
+ <property name="show_sql" value="true" />
+ <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
+ </properties>
+ </persistence-unit>
+</persistence>
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/PetStoreResource_orig.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/PetStoreResource_orig.json
deleted file mode 100644
index 2b290a6..0000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/PetStoreResource_orig.json
+++ /dev/null
@@ -1,1048 +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. *
-// ***************************************************************************************************************************
-
-{
- "swagger": "2.0",
- "info": {
- "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
- "version": "1.0.0",
- "title": "Swagger Petstore",
- "termsOfService": "http://swagger.io/terms/",
- "contact": {
- "email": "apiteam@swagger.io"
- },
- "license": {
- "name": "Apache 2.0",
- "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
- }
- },
- "host": "petstore.swagger.io",
- "basePath": "/v2",
- "tags": [
- {
- "name": "pet",
- "description": "Everything about your Pets",
- "externalDocs": {
- "description": "Find out more",
- "url": "http://swagger.io"
- }
- },
- {
- "name": "store",
- "description": "Access to Petstore orders"
- },
- {
- "name": "user",
- "description": "Operations about user",
- "externalDocs": {
- "description": "Find out more about our store",
- "url": "http://swagger.io"
- }
- }
- ],
- "schemes": [
- "http"
- ],
- "paths": {
- "/pet": {
- "post": {
- "tags": [
- "pet"
- ],
- "summary": "Add a new pet to the store",
- "description": "",
- "operationId": "addPet",
- "consumes": [
- "application/json",
- "application/xml"
- ],
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "Pet object that needs to be added to the store",
- "required": true,
- "schema": {
- "$ref": "#/definitions/Pet"
- }
- }
- ],
- "responses": {
- "405": {
- "description": "Invalid input"
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ]
- },
- "put": {
- "tags": [
- "pet"
- ],
- "summary": "Update an existing pet",
- "description": "",
- "operationId": "updatePet",
- "consumes": [
- "application/json",
- "application/xml"
- ],
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "Pet object that needs to be added to the store",
- "required": true,
- "schema": {
- "$ref": "#/definitions/Pet"
- }
- }
- ],
- "responses": {
- "400": {
- "description": "Invalid ID supplied"
- },
- "404": {
- "description": "Pet not found"
- },
- "405": {
- "description": "Validation exception"
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ]
- }
- },
- "/pet/findByStatus": {
- "get": {
- "tags": [
- "pet"
- ],
- "summary": "Finds Pets by status",
- "description": "Multiple status values can be provided with comma separated strings",
- "operationId": "findPetsByStatus",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "status",
- "in": "query",
- "description": "Status values that need to be considered for filter",
- "required": true,
- "type": "array",
- "items": {
- "type": "string",
- "enum": [
- "available",
- "pending",
- "sold"
- ],
- "default": "available"
- },
- "collectionFormat": "multi"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/Pet"
- }
- }
- },
- "400": {
- "description": "Invalid status value"
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ]
- }
- },
- "/pet/findByTags": {
- "get": {
- "tags": [
- "pet"
- ],
- "summary": "Finds Pets by tags",
- "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
- "operationId": "findPetsByTags",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "tags",
- "in": "query",
- "description": "Tags to filter by",
- "required": true,
- "type": "array",
- "items": {
- "type": "string"
- },
- "collectionFormat": "multi"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/Pet"
- }
- }
- },
- "400": {
- "description": "Invalid tag value"
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ],
- "deprecated": true
- }
- },
- "/pet/{petId}": {
- "get": {
- "tags": [
- "pet"
- ],
- "summary": "Find pet by ID",
- "description": "Returns a single pet",
- "operationId": "getPetById",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "petId",
- "in": "path",
- "description": "ID of pet to return",
- "required": true,
- "type": "integer",
- "format": "int64"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "$ref": "#/definitions/Pet"
- }
- },
- "400": {
- "description": "Invalid ID supplied"
- },
- "404": {
- "description": "Pet not found"
- }
- },
- "security": [
- {
- "api_key": []
- }
- ]
- },
- "post": {
- "tags": [
- "pet"
- ],
- "summary": "Updates a pet in the store with form data",
- "description": "",
- "operationId": "updatePetWithForm",
- "consumes": [
- "application/x-www-form-urlencoded"
- ],
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "petId",
- "in": "path",
- "description": "ID of pet that needs to be updated",
- "required": true,
- "type": "integer",
- "format": "int64"
- },
- {
- "name": "name",
- "in": "formData",
- "description": "Updated name of the pet",
- "required": false,
- "type": "string"
- },
- {
- "name": "status",
- "in": "formData",
- "description": "Updated status of the pet",
- "required": false,
- "type": "string"
- }
- ],
- "responses": {
- "405": {
- "description": "Invalid input"
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ]
- },
- "delete": {
- "tags": [
- "pet"
- ],
- "summary": "Deletes a pet",
- "description": "",
- "operationId": "deletePet",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "api_key",
- "in": "header",
- "required": false,
- "type": "string"
- },
- {
- "name": "petId",
- "in": "path",
- "description": "Pet id to delete",
- "required": true,
- "type": "integer",
- "format": "int64"
- }
- ],
- "responses": {
- "400": {
- "description": "Invalid ID supplied"
- },
- "404": {
- "description": "Pet not found"
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ]
- }
- },
- "/pet/{petId}/uploadImage": {
- "post": {
- "tags": [
- "pet"
- ],
- "summary": "uploads an image",
- "description": "",
- "operationId": "uploadFile",
- "consumes": [
- "multipart/form-data"
- ],
- "produces": [
- "application/json"
- ],
- "parameters": [
- {
- "name": "petId",
- "in": "path",
- "description": "ID of pet to update",
- "required": true,
- "type": "integer",
- "format": "int64"
- },
- {
- "name": "additionalMetadata",
- "in": "formData",
- "description": "Additional data to pass to server",
- "required": false,
- "type": "string"
- },
- {
- "name": "file",
- "in": "formData",
- "description": "file to upload",
- "required": false,
- "type": "file"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "$ref": "#/definitions/ApiResponse"
- }
- }
- },
- "security": [
- {
- "petstore_auth": [
- "write:pets",
- "read:pets"
- ]
- }
- ]
- }
- },
- "/store/inventory": {
- "get": {
- "tags": [
- "store"
- ],
- "summary": "Returns pet inventories by status",
- "description": "Returns a map of status codes to quantities",
- "operationId": "getInventory",
- "produces": [
- "application/json"
- ],
- "parameters": [],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "type": "object",
- "additionalProperties": {
- "type": "integer",
- "format": "int32"
- }
- }
- }
- },
- "security": [
- {
- "api_key": []
- }
- ]
- }
- },
- "/store/order": {
- "post": {
- "tags": [
- "store"
- ],
- "summary": "Place an order for a pet",
- "description": "",
- "operationId": "placeOrder",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "order placed for purchasing the pet",
- "required": true,
- "schema": {
- "$ref": "#/definitions/Order"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "$ref": "#/definitions/Order"
- }
- },
- "400": {
- "description": "Invalid Order"
- }
- }
- }
- },
- "/store/order/{orderId}": {
- "get": {
- "tags": [
- "store"
- ],
- "summary": "Find purchase order by ID",
- "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions",
- "operationId": "getOrderById",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "orderId",
- "in": "path",
- "description": "ID of pet that needs to be fetched",
- "required": true,
- "type": "integer",
- "maximum": 10.0,
- "minimum": 1.0,
- "format": "int64"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "$ref": "#/definitions/Order"
- }
- },
- "400": {
- "description": "Invalid ID supplied"
- },
- "404": {
- "description": "Order not found"
- }
- }
- },
- "delete": {
- "tags": [
- "store"
- ],
- "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",
- "operationId": "deleteOrder",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "orderId",
- "in": "path",
- "description": "ID of the order that needs to be deleted",
- "required": true,
- "type": "integer",
- "minimum": 1.0,
- "format": "int64"
- }
- ],
- "responses": {
- "400": {
- "description": "Invalid ID supplied"
- },
- "404": {
- "description": "Order not found"
- }
- }
- }
- },
- "/user": {
- "post": {
- "tags": [
- "user"
- ],
- "summary": "Create user",
- "description": "This can only be done by the logged in user.",
- "operationId": "createUser",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "Created user object",
- "required": true,
- "schema": {
- "$ref": "#/definitions/User"
- }
- }
- ],
- "responses": {
- "default": {
- "description": "successful operation"
- }
- }
- }
- },
- "/user/createWithArray": {
- "post": {
- "tags": [
- "user"
- ],
- "summary": "Creates list of users with given input array",
- "description": "",
- "operationId": "createUsersWithArrayInput",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "List of user object",
- "required": true,
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/User"
- }
- }
- }
- ],
- "responses": {
- "default": {
- "description": "successful operation"
- }
- }
- }
- },
- "/user/createWithList": {
- "post": {
- "tags": [
- "user"
- ],
- "summary": "Creates list of users with given input array",
- "description": "",
- "operationId": "createUsersWithListInput",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "List of user object",
- "required": true,
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/User"
- }
- }
- }
- ],
- "responses": {
- "default": {
- "description": "successful operation"
- }
- }
- }
- },
- "/user/login": {
- "get": {
- "tags": [
- "user"
- ],
- "summary": "Logs user into the system",
- "description": "",
- "operationId": "loginUser",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "username",
- "in": "query",
- "description": "The user name for login",
- "required": true,
- "type": "string"
- },
- {
- "name": "password",
- "in": "query",
- "description": "The password for login in clear text",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "type": "string"
- },
- "headers": {
- "X-Rate-Limit": {
- "type": "integer",
- "format": "int32",
- "description": "calls per hour allowed by the user"
- },
- "X-Expires-After": {
- "type": "string",
- "format": "date-time",
- "description": "date in UTC when token expires"
- }
- }
- },
- "400": {
- "description": "Invalid username/password supplied"
- }
- }
- }
- },
- "/user/logout": {
- "get": {
- "tags": [
- "user"
- ],
- "summary": "Logs out current logged in user session",
- "description": "",
- "operationId": "logoutUser",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [],
- "responses": {
- "default": {
- "description": "successful operation"
- }
- }
- }
- },
- "/user/{username}": {
- "get": {
- "tags": [
- "user"
- ],
- "summary": "Get user by user name",
- "description": "",
- "operationId": "getUserByName",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "username",
- "in": "path",
- "description": "The name that needs to be fetched. Use user1 for testing. ",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "200": {
- "description": "successful operation",
- "schema": {
- "$ref": "#/definitions/User"
- }
- },
- "400": {
- "description": "Invalid username supplied"
- },
- "404": {
- "description": "User not found"
- }
- }
- },
- "put": {
- "tags": [
- "user"
- ],
- "summary": "Updated user",
- "description": "This can only be done by the logged in user.",
- "operationId": "updateUser",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "username",
- "in": "path",
- "description": "name that need to be updated",
- "required": true,
- "type": "string"
- },
- {
- "in": "body",
- "name": "body",
- "description": "Updated user object",
- "required": true,
- "schema": {
- "$ref": "#/definitions/User"
- }
- }
- ],
- "responses": {
- "400": {
- "description": "Invalid user supplied"
- },
- "404": {
- "description": "User not found"
- }
- }
- },
- "delete": {
- "tags": [
- "user"
- ],
- "summary": "Delete user",
- "description": "This can only be done by the logged in user.",
- "operationId": "deleteUser",
- "produces": [
- "application/xml",
- "application/json"
- ],
- "parameters": [
- {
- "name": "username",
- "in": "path",
- "description": "The name that needs to be deleted",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "400": {
- "description": "Invalid username supplied"
- },
- "404": {
- "description": "User not found"
- }
- }
- }
- }
- },
- "securityDefinitions": {
- "petstore_auth": {
- "type": "oauth2",
- "authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
- "flow": "implicit",
- "scopes": {
- "write:pets": "modify pets in your account",
- "read:pets": "read your pets"
- }
- },
- "api_key": {
- "type": "apiKey",
- "name": "api_key",
- "in": "header"
- }
- },
- "definitions": {
- "Order": {
- "type": "object",
- "properties": {
- "id": {
- "type": "integer",
- "format": "int64"
- },
- "petId": {
- "type": "integer",
- "format": "int64"
- },
- "quantity": {
- "type": "integer",
- "format": "int32"
- },
- "shipDate": {
- "type": "string",
- "format": "date-time"
- },
- "status": {
- "type": "string",
- "description": "Order Status",
- "enum": [
- "placed",
- "approved",
- "delivered"
- ]
- },
- "complete": {
- "type": "boolean",
- "default": false
- }
- },
- "xml": {
- "name": "Order"
- }
- },
- "User": {
- "type": "object",
- "properties": {
- "id": {
- "type": "integer",
- "format": "int64"
- },
- "username": {
- "type": "string"
- },
- "firstName": {
- "type": "string"
- },
- "lastName": {
- "type": "string"
- },
- "email": {
- "type": "string"
- },
- "password": {
- "type": "string"
- },
- "phone": {
- "type": "string"
- },
- "userStatus": {
- "type": "integer",
- "format": "int32",
- "description": "User Status"
- }
- },
- "xml": {
- "name": "User"
- }
- },
- "Category": {
- "type": "object",
- "properties": {
- "id": {
- "type": "integer",
- "format": "int64"
- },
- "name": {
- "type": "string"
- }
- },
- "xml": {
- "name": "Category"
- }
- },
- "Tag": {
- "type": "object",
- "properties": {
- "id": {
- "type": "integer",
- "format": "int64"
- },
- "name": {
- "type": "string"
- }
- },
- "xml": {
- "name": "Tag"
- }
- },
- "Pet": {
- "type": "object",
- "required": [
- "name",
- "photoUrls"
- ],
- "properties": {
- "id": {
- "type": "integer",
- "format": "int64"
- },
- "category": {
- "$ref": "#/definitions/Category"
- },
- "name": {
- "type": "string",
- "example": "doggie"
- },
- "photoUrls": {
- "type": "array",
- "xml": {
- "name": "photoUrl",
- "wrapped": true
- },
- "items": {
- "type": "string"
- }
- },
- "tags": {
- "type": "array",
- "xml": {
- "name": "tag",
- "wrapped": true
- },
- "items": {
- "$ref": "#/definitions/Tag"
- }
- },
- "status": {
- "type": "string",
- "description": "pet status in the store",
- "enum": [
- "available",
- "pending",
- "sold"
- ]
- }
- },
- "xml": {
- "name": "Pet"
- }
- },
- "ApiResponse": {
- "type": "object",
- "properties": {
- "code": {
- "type": "integer",
- "format": "int32"
- },
- "type": {
- "type": "string"
- },
- "message": {
- "type": "string"
- }
- }
- }
- },
- "externalDocs": {
- "description": "Find out more about Swagger",
- "url": "http://swagger.io"
- }
-}
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Pets.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Pets.json
deleted file mode 100644
index 9976a4a..0000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Pets.json
+++ /dev/null
@@ -1,24 +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. *
-// ***************************************************************************************************************************
-
-[
- {id:101, species:'cat', name:'Mr. Frisky', price:39.99, tags:['friendly'], status:'AVAILABLE'},
- {id:102, species:'dog', name:'Kibbles', price:99.99, tags:['loyal'], status:'AVAILABLE'},
- {id:103, species:'rabbit', name:'Hoppy', price:49.99, tags:['friendly','smells nice'], status:'AVAILABLE'},
- {id:104, species:'rabbit', name:'Hoppy 2', price:49.99, status:'AVAILABLE'},
- {id:105, species:'rabbit', name:'Hoppy 3', price:49.99, status:'AVAILABLE'},
- {id:106, species:'rabbit', name:'Hoppy 4', price:49.99, status:'AVAILABLE'},
- {id:107, species:'fish', name:'Gorton', price:1.99, status:'PENDING'},
- {id:108, species:'mouse', name:'Hackwrench', price:4.99, status:'SOLD'},
- {id:109, species:'snake', name:'Just Snake', price:9.99, status:'SOLD'}
-]
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Orders.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Orders.json
similarity index 100%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Orders.json
rename to juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Orders.json
diff --git a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Users.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Pets.json
similarity index 69%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Users.json
rename to juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Pets.json
index 5e340c1..c0aa31f 100644
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Users.json
+++ b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Pets.json
@@ -12,7 +12,13 @@
// ***************************************************************************************************************************
[
- {username:'mariewatson',firstName:'Marie',lastName:'Watson',email:'marie.watson@fakemail.com',password:'123456',phone:'444-555-7777',userStatus:'ACTIVE'},
- {username:'danielvaughn',firstName:'Daniel',lastName:'Vaughn',email:'daniel.vaughn@test.com',password:'123456',phone:'666-777-3333',userStatus:'ACTIVE'},
- {username:'brendafuller',firstName:'Brenda',lastName:'Fuller',email:'brenda.fuller@example.com',password:'123456',phone:'777-888-3333',userStatus:'INACTIVE'}
-]
+ {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-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Species.json b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Users.json
similarity index 77%
rename from juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Species.json
rename to juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Users.json
index fc5ecbf..7f02a3c 100644
--- a/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/Species.json
+++ b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/petstore/init/Users.json
@@ -12,10 +12,7 @@
// ***************************************************************************************************************************
[
- {id:101, name:'cat'},
- {id:102, name:'dog'},
- {id:103, name:'rabbit'},
- {id:104, name:'fish'},
- {id:105, name:'mouse'},
- {id:106, name:'snake'}
+ {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-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
index 13e737d..97f088e 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
@@ -107,7 +107,7 @@ public class RemoteMethodMeta {
methodReturn = new RemoteMethodReturn(m);
- fullPath = path.indexOf("://") != -1 ? path : (parentPath.isEmpty() ? urlEncode(path) : (trimSlashes(parentPath) + '/' + urlEncode(path)));
+ fullPath = path.indexOf("://") != -1 ? path : (parentPath.isEmpty() ? urlEncodePath(path) : (trimSlashes(parentPath) + '/' + urlEncodePath(path)));
for (int i = 0; i < m.getParameterTypes().length; i++) {
RemoteMethodArg rma = RemoteMethodArg.create(m, i);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index 1e4520f..de95ef6 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -141,6 +141,8 @@ public class BasicRestCallHandler implements RestCallHandler {
req = createRequest(r1);
RestResponse res = createResponse(req, r2);
+ context.setRequest(req);
+ context.setResponse(res);
String method = req.getMethod();
String methodUC = method.toUpperCase(Locale.ENGLISH);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 0bb1bf7..5b5a505 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3042,6 +3042,9 @@ public final class RestContext extends BeanContext {
private final ClasspathResourceManager staticResourceManager;
private final ConcurrentHashMap<Integer,AtomicInteger> stackTraceHashes = new ConcurrentHashMap<>();
+ private final ThreadLocal<RestRequest> req = new ThreadLocal<>();
+ private final ThreadLocal<RestResponse> res = new ThreadLocal<>();
+
/**
* Constructor.
*
@@ -4763,4 +4766,39 @@ public final class RestContext extends BeanContext {
public BeanSessionArgs createDefaultSessionArgs() {
throw new NoSuchMethodError();
}
+
+ /**
+ * Returns the HTTP request object for the current request.
+ *
+ * @return The HTTP request object, or <jk>null</jk> if it hasn't been created.
+ */
+ public RestRequest getRequest() {
+ return req.get();
+ }
+
+ void setRequest(RestRequest req) {
+ this.req.set(req);
+ }
+
+ /**
+ * Returns the HTTP response object for the current request.
+ *
+ * @return The HTTP response object, or <jk>null</jk> if it hasn't been created.
+ */
+ public RestResponse getResponse() {
+ return res.get();
+ }
+
+ void setResponse(RestResponse res) {
+ this.res.set(res);
+ }
+
+ /**
+ * Clear any request state information on this context.
+ * This should always be called in a finally block in the RestServlet.
+ */
+ void clearState() {
+ req.remove();
+ res.remove();
+ }
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index e8f218a..61c5bbd 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -414,7 +414,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
*/
@Override /* ServletResponse */
public PrintWriter getWriter() throws IOException {
- return getWriter(true);
+ return getWriter(true, false);
}
/**
@@ -435,7 +435,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
setContentType(contentType);
setHeader("X-Content-Type-Options", "nosniff");
setHeader("Content-Encoding", "identity");
- return getWriter();
+ return getWriter(true, true);
}
/**
@@ -448,11 +448,11 @@ public final class RestResponse extends HttpServletResponseWrapper {
* @throws IOException
*/
public FinishablePrintWriter getNegotiatedWriter() throws NotAcceptable, IOException {
- return getWriter(false);
+ return getWriter(false, false);
}
@SuppressWarnings("resource")
- private FinishablePrintWriter getWriter(boolean raw) throws NotAcceptable, IOException {
+ private FinishablePrintWriter getWriter(boolean raw, boolean autoflush) throws NotAcceptable, IOException {
if (w != null)
return w;
@@ -462,7 +462,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
try {
OutputStream out = (raw ? getOutputStream() : getNegotiatedOutputStream());
- w = new FinishablePrintWriter(out, getCharacterEncoding());
+ w = new FinishablePrintWriter(out, getCharacterEncoding(), autoflush);
return w;
} catch (UnsupportedEncodingException e) {
String ce = getCharacterEncoding();
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
index 8dba115..05ebb3a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
@@ -42,7 +42,6 @@ public abstract class RestServlet extends HttpServlet {
private boolean isInitialized = false;
private Exception initException;
-
@Override /* Servlet */
public final synchronized void init(ServletConfig servletConfig) throws ServletException {
try {
@@ -148,6 +147,8 @@ public abstract class RestServlet extends HttpServlet {
r2.sendError(SC_INTERNAL_SERVER_ERROR, e.getLocalizedMessage());
} catch (Throwable e) {
r2.sendError(SC_INTERNAL_SERVER_ERROR, e.getLocalizedMessage());
+ } finally {
+ context.clearState();
}
}
@@ -206,6 +207,24 @@ public abstract class RestServlet extends HttpServlet {
}
}
+ /**
+ * Returns the current HTTP request.
+ *
+ * @return The current HTTP request, or <jk>null</jk> if it wasn't created.
+ */
+ public RestRequest getRequest() {
+ return context.getRequest();
+ }
+
+ /**
+ * Returns the current HTTP response.
+ *
+ * @return The current HTTP response, or <jk>null</jk> if it wasn't created.
+ */
+ public RestResponse getResponse() {
+ return context.getResponse();
+ }
+
@Override /* GenericServlet */
public synchronized void destroy() {
if (context != null)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishablePrintWriter.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishablePrintWriter.java
index 904dcb1..63495c5 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishablePrintWriter.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishablePrintWriter.java
@@ -28,10 +28,11 @@ public class FinishablePrintWriter extends PrintWriter implements Finishable {
*
* @param out The wrapped output stream.
* @param characterEncoding The character encoding of the output stream.
+ * @param autoFlush Automatically flush after every println.
* @throws IOException
*/
- public FinishablePrintWriter(OutputStream out, String characterEncoding) throws IOException {
- super(new OutputStreamWriter(out, characterEncoding));
+ public FinishablePrintWriter(OutputStream out, String characterEncoding, boolean autoFlush) throws IOException {
+ super(new OutputStreamWriter(out, characterEncoding), autoFlush);
f = (out instanceof Finishable ? (Finishable)out : null);
}