Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,244 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static java.util.logging.Level.*;
+import static javax.servlet.http.HttpServletResponse.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.io.*;
+import java.text.*;
+import java.util.logging.*;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Servlet implementation of a REST resource.
+ *
+ * <p>
+ * Refer to <a class="doclink" href="package-summary.html#TOC">REST Servlet 
API</a> for information about using this
+ * class.
+ */
+@SuppressWarnings("hiding")
+public abstract class RestServlet extends HttpServlet {
+
+       private static final long serialVersionUID = 1L;
+
+       private RestConfig config;
+       private RestContext context;
+       private volatile boolean isInitialized = false;
+       private Exception initException;
+
+
+       @Override /* Servlet */
+       public final synchronized void init(ServletConfig servletConfig) throws 
ServletException {
+               try {
+                       RestConfig rsc = new RestConfig(servletConfig, 
this.getClass(), null);
+                       rsc.init(this);
+                       RestContext context = createContext(rsc);
+                       super.init(servletConfig);
+                       context.postInit();
+                       context.postInitChildFirst();
+               } catch (RestException e) {
+                       // Thrown RestExceptions are simply caught and 
re-thrown on subsequent calls to service().
+                       initException = e;
+                       log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
+               } catch (ServletException e) {
+                       initException = e;
+                       log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
+                       throw e;
+               } catch (Exception e) {
+                       initException = e;
+                       log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
+                       throw new ServletException(e);
+               } catch (Throwable e) {
+                       initException = new Exception(e);
+                       log(SEVERE, e, "Servlet init error on class ''{0}''", 
getClass().getName());
+                       throw new ServletException(e);
+               } finally {
+                       isInitialized = true;
+               }
+       }
+
+       /*
+        * Bypasses the init(ServletConfig) method and just calls the 
super.init(ServletConfig) method directly.
+        * Used when subclasses of RestServlet are attached as child resources.
+        */
+       void innerInit(ServletConfig servletConfig) throws ServletException {
+               super.init(servletConfig);
+       }
+
+       /*
+        * Sets the context object for this servlet.
+        * Used when subclasses of RestServlet are attached as child resources.
+        */
+       void setContext(RestContext context) {
+               this.config = context.config;
+               this.context = context;
+       }
+
+       /**
+        * Convenience method if you want to perform initialization on your 
resource after all configuration settings
+        * have been made.
+        *
+        * <p>
+        * This allows you to get access to the {@link RestContext} object 
during initialization.
+        *
+        * <p>
+        * The default implementation does nothing.
+        *
+        * @param context The servlet context containing all the set-in-stone 
configurations for this resource.
+        * @throws Exception Any exception can be thrown to signal an 
initialization failure.
+        */
+       public synchronized void init(RestContext context) throws Exception {}
+
+
+       private synchronized RestContext createContext(RestConfig config) 
throws Exception {
+               if (! isInitialized) {
+                       this.config = config;
+                       this.context = new RestContext(this, 
this.getServletContext(), config);
+                       this.isInitialized = true;
+               }
+               return context;
+       }
+
+
+       
//--------------------------------------------------------------------------------
+       // Other methods
+       
//--------------------------------------------------------------------------------
+
+       /**
+        * The main service method.
+        *
+        * <p>
+        * Subclasses can optionally override this method if they want to 
tailor the behavior of requests.
+        */
+       @Override /* Servlet */
+       public void service(HttpServletRequest r1, HttpServletResponse r2) 
throws ServletException, IOException {
+               try {
+                       if (initException != null) {
+                               if (initException instanceof RestException)
+                                       throw (RestException)initException;
+                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, initException);
+                       }
+                       if (context == null)
+                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, "Servlet {0} not initialized.  
init(RestConfig) was not called.  This can occur if you've overridden this 
method but didn't call super.init(RestConfig).", getClass().getName());
+                       if (! isInitialized)
+                               throw new 
RestException(SC_INTERNAL_SERVER_ERROR, "Servlet {0} has not been initialized", 
getClass().getName());
+
+                       context.getCallHandler().service(r1, r2);
+
+               } catch (RestException e) {
+                       r2.sendError(SC_INTERNAL_SERVER_ERROR, 
e.getLocalizedMessage());
+               } catch (Throwable e) {
+                       r2.sendError(SC_INTERNAL_SERVER_ERROR, 
e.getLocalizedMessage());
+               }
+       }
+
+       /**
+        * Returns the read-only context object that contains all the 
configuration information about this resource.
+        *
+        * <p>
+        * This object is <jk>null</jk> during the call to {@link 
#init(ServletConfig)} but is populated by the time
+        * {@link #init()} is called.
+        *
+        * <p>
+        * Resource classes that don't extend from {@link RestServlet} can add 
the following method to their class to get
+        * access to this context object:
+        * <p class='bcode'>
+        *      <jk>public void</jk> init(RestServletContext context) 
<jk>throws</jk> Exception;
+        * </p>
+        *
+        * @return The context information on this servlet.
+        */
+       protected RestContext getContext() {
+               return context;
+       }
+
+       /**
+        * Convenience method for calling 
<code>getContext().getLogger().log(level, msg, args);</code>
+        *
+        * @param level The log level.
+        * @param msg The message to log.
+        * @param args Optional {@link MessageFormat}-style arguments.
+        */
+       protected void log(Level level, String msg, Object...args) {
+               if (context != null)
+                       context.getLogger().log(level, msg, args);
+       }
+
+       /**
+        * Convenience method for calling 
<code>getContext().getLogger().log(level, cause, msg, args);</code>
+        *
+        * @param level The log level.
+        * @param cause The cause.
+        * @param msg The message to log.
+        * @param args Optional {@link MessageFormat}-style arguments.
+        */
+       protected void log(Level level, Throwable cause, String msg, 
Object...args) {
+               if (context != null)
+                       context.getLogger().log(level, cause, msg, args);
+               else {
+                       // If context failed to initialize, log to the console.
+                       System.err.println(format(msg, args));
+                       if (cause != null)
+                               cause.printStackTrace();
+               }
+       }
+
+       @Override /* GenericServlet */
+       public RestConfig getServletConfig() {
+               return config;
+       }
+
+       @Override /* GenericServlet */
+       public void destroy() {
+               if (context != null)
+                       context.destroy();
+               super.destroy();
+       }
+
+       /**
+        * Convenience method for calling 
<code>getContext().getMessages();</code>
+        *
+        * @return The resource bundle for this resource.  Never <jk>null</jk>.
+        * @see RestContext#getProperties()
+        */
+       public MessageBundle getMessages() {
+               return context.getMessages();
+       }
+
+       /**
+        * Convenience method for calling 
<code>getContext().getProperties();</code>
+        *
+        * @return The resource properties as an {@link ObjectMap}.
+        * @see RestContext#getProperties()
+        */
+       public ObjectMap getProperties() {
+               return getContext().getProperties();
+       }
+
+       /**
+        * Convenience method for calling 
<code>getContext().getBeanContext();</code>
+        *
+        * @return The bean context used for parsing path variables and header 
values.
+        * @see RestContext#getBeanContext()
+        */
+       public BeanContext getBeanContext() {
+               return getContext().getBeanContext();
+       }
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,230 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.rest.RestContext.*;
+
+import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.html.*;
+import org.apache.juneau.jso.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.msgpack.*;
+import org.apache.juneau.plaintext.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.soap.*;
+import org.apache.juneau.uon.*;
+import org.apache.juneau.urlencoding.*;
+import org.apache.juneau.xml.*;
+
+/**
+ * Subclass of {@link RestServlet} with default serializers and parsers 
defined.
+ *
+ * <p>
+ * Supports the following request <code>Accept</code> header values with the 
resulting response <code>Content-Type</code>:
+ * <table class='styled'>
+ *     <tr>
+ *             <th>Accept</th>
+ *             <th>Content-Type</th>
+ *             <th>Serializer</th>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>application/json<br>text/json</td>
+ *             <td class='code'>application/json</td>
+ *             <td>{@link JsonSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td 
class='code'>application/json+simple<br>text/json+simple</td>
+ *             <td class='code'>application/json</td>
+ *             <td>{@link org.apache.juneau.json.JsonSerializer.Simple}</td>
+ *     </tr>
+ *     <tr>
+ *             <td 
class='code'>application/json+schema<br>text/json+schema</td>
+ *             <td class='code'>application/json</td>
+ *             <td>{@link JsonSchemaSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/xml</td>
+ *             <td class='code'>text/xml</td>
+ *             <td>{@link XmlDocSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/xml+schema</td>
+ *             <td class='code'>text/xml</td>
+ *             <td>{@link XmlSchemaDocSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/html</td>
+ *             <td class='code'>text/html</td>
+ *             <td>{@link HtmlDocSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/html+stripped</td>
+ *             <td class='code'>text/html</td>
+ *             <td>{@link HtmlStrippedDocSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/uon</td>
+ *             <td class='code'>text/uon</td>
+ *             <td>{@link UonSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>application/x-www-form-urlencoded</td>
+ *             <td class='code'>application/x-www-form-urlencoded</td>
+ *             <td>{@link UrlEncodingSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/xml+soap</td>
+ *             <td class='code'>text/xml</td>
+ *             <td>{@link SoapXmlSerializer}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/plain</td>
+ *             <td class='code'>text/plain</td>
+ *             <td>{@link PlainTextSerializer}</td>
+ *     </tr>
+ * </table>
+ * <p>
+ * Supports the following request <code>Content-Type</code> header values:
+ * </p>
+ * <table class='styled'>
+ *     <tr>
+ *             <th>Content-Type</th>
+ *             <th>Parser</th>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>application/json<br>text/json</td>
+ *             <td>{@link JsonParser}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/xml<br>application/xml</td>
+ *             <td>{@link XmlParser}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/html<br>text/html+stripped</td>
+ *             <td>{@link HtmlParser}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/uon</td>
+ *             <td>{@link UonParser}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>application/x-www-form-urlencoded</td>
+ *             <td>{@link UrlEncodingParser}</td>
+ *     </tr>
+ *     <tr>
+ *             <td class='code'>text/plain</td>
+ *             <td>{@link PlainTextParser}</td>
+ *     </tr>
+ * </table>
+ *
+ * <p>
+ * It should be noted that we do NOT add {@link JsoParser} to the list of 
parsers since this could cause security
+ * issues.
+ * Use caution when using this particular parser as it could inadvertently 
cause code execution security holes.
+ *
+ * <p>
+ * The list of serializers and parsers can be appended to using the
+ * {@link RestResource#serializers() @RestResource.serializers()} and
+ * {@link RestResource#parsers() @RestResource.parsers()} annotations on 
subclasses.
+ *
+ * <p>
+ * This subclass also provides a default OPTIONS page by implementing a {@link 
#getOptions(RestRequest)} that returns a
+ * POJO consisting of beans describing the class.
+ * <img class='bordered' src='doc-files/OptionsPage.png'>
+ *
+ * <p>
+ * The OPTIONS page can be modified or augmented by overriding this method and 
providing your own data.
+ *
+ * <h6 class='topic'>Other Notes</h6>
+ * <ul class='spaced-list'>
+ *     <li>
+ *             Provides a default HTML stylesheet by setting {@link 
HtmlDoc#stylesheet() @HtmlDoc.stylesheet()}
+ *             to <js>"styles/juneau.css"</js>.
+ *     <li>
+ *             Provides a default favicon by setting {@link 
RestResource#favicon() @RestResource.favicon()} to
+ *             <js>"juneau.ico"</js>.
+ *     <li>
+ *             Provides a default classpath entry "htdocs" by setting
+ *             {@link RestResource#staticFiles() @RestResource.staticFiles()} 
to <js>"{htdocs:'htdocs'}"</js>.
+ *             This allows files inside the 
<code>[servletPackage].htdocs</code> package to be served up under the URL
+ *             <code>/servletPath/htdocs</code>.
+ * </ul>
+ */
+@RestResource(
+       serializers={
+               HtmlDocSerializer.class, // HTML must be listed first because 
Internet Explore does not include text/html in their Accept header.
+               HtmlStrippedDocSerializer.class,
+               HtmlSchemaDocSerializer.class,
+               JsonSerializer.class,
+               JsonSerializer.Simple.class,
+               JsonSchemaSerializer.class,
+               XmlDocSerializer.class,
+               XmlSchemaDocSerializer.class,
+               UonSerializer.class,
+               UrlEncodingSerializer.class,
+               MsgPackSerializer.class,
+               SoapXmlSerializer.class,
+               PlainTextSerializer.class
+       },
+       parsers={
+               JsonParser.class,
+               XmlParser.class,
+               HtmlParser.class,
+               UonParser.class,
+               UrlEncodingParser.class,
+               MsgPackParser.class,
+               PlainTextParser.class
+       },
+       properties={
+               // Allow &method parameter on safe HTTP methods.
+               @Property(name=REST_allowMethodParam, value="OPTIONS"),
+       },
+       htmldoc=@HtmlDoc(
+               header={
+                       "<h1>$R{servletTitle}</h1>",
+                       "<h2>$R{methodSummary,$R{servletDescription}}</h2>",
+                       "<a href='http://juneau.apache.org'><img 
src='$U{servlet:/htdocs/juneau.png}' 
style='position:absolute;top:5;right:5;background-color:transparent;height:30px'/></a>"
+               },
+               stylesheet="servlet:/styles/light.css"
+       ),
+
+       // The location on the classpath or file system of the fav-icon.
+       favicon="htdocs/juneau.png",
+
+       // These are static files that are served up by the servlet under the 
specified sub-paths.
+       staticFiles="{htdocs:'htdocs',styles:'styles'}"
+)
+public abstract class RestServletDefault extends RestServlet {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * [OPTIONS /*] - Show resource options.
+        *
+        * @param req The HTTP request.
+        * @return A bean containing the contents for the OPTIONS page.
+        */
+       @RestMethod(name="OPTIONS", path="/*",
+               htmldoc=@HtmlDoc(
+                       links={
+                               "back: servlet:/",
+                               "json: 
servlet:/?method=OPTIONS&Accept=text/json&plainText=true"
+                       },
+                       aside="NONE"
+               ),
+               summary="Swagger documentation",
+               description="Auto-generated swagger documentation for this 
resource"
+       )
+       public Swagger getOptions(RestRequest req) {
+               return req.getSwagger();
+       }
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletDefault.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletException.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletException.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletException.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,49 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.text.*;
+
+import javax.servlet.*;
+
+/**
+ * General exception thrown from {@link RestServlet} during construction or 
initialization.
+ */
+public class RestServletException extends ServletException {
+
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * Constructor.
+        *
+        * @param message The detailed message.
+        * @param args Optional {@link MessageFormat}-style arguments.
+        */
+       public RestServletException(String message, Object...args) {
+               super(format(message, args));
+       }
+
+       /**
+        * Sets the inner cause for this exception.
+        *
+        * @param cause The inner cause.
+        * @return This object (for method chaining).
+        */
+       @Override /* Throwable */
+       public synchronized RestServletException initCause(Throwable cause) {
+               super.initCause(cause);
+               return this;
+       }
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletGroupDefault.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletGroupDefault.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletGroupDefault.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,43 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.labels.*;
+
+/**
+ * Specialized subclass of {@link RestServletDefault} for showing "group" 
pages.
+ *
+ * <p>
+ * Group pages consist of simple lists of child resource URLs and their labels.
+ * They're meant to be used as jumping-off points for child resources.
+ *
+ * <p>
+ * Child resources are specified using the {@link RestResource#children()} 
annotation.
+ */
+@RestResource()
+public abstract class RestServletGroupDefault extends RestServletDefault {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * [GET /] - Get child resources.
+        *
+        * @param req The HTTP request.
+        * @return The bean containing links to the child resources.
+        */
+       @RestMethod(name="GET", path="/", description="Child resources")
+       public ChildResourceDescriptions getChildren(RestRequest req) {
+               return new ChildResourceDescriptions(getContext(), req);
+       }
+}
+

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServletGroupDefault.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,226 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.util.*;
+import java.util.regex.*;
+
+import javax.servlet.http.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Various reusable utility methods.
+ */
+public final class RestUtils {
+
+       /**
+        * Returns readable text for an HTTP response code.
+        *
+        * @param rc The HTTP response code.
+        * @return Readable text for an HTTP response code, or <jk>null</jk> if 
it's an invalid code.
+        */
+       public static String getHttpResponseText(int rc) {
+               return httpMsgs.get(rc);
+       }
+
+       private static Map<Integer,String> httpMsgs = new AMap<Integer,String>()
+               .append(200, "OK")
+               .append(201, "Created")
+               .append(202, "Accepted")
+               .append(203, "Non-Authoritative Information")
+               .append(204, "No Content")
+               .append(205, "Reset Content")
+               .append(206, "Partial Content")
+               .append(300, "Multiple Choices")
+               .append(301, "Moved Permanently")
+               .append(302, "Temporary Redirect")
+               .append(303, "See Other")
+               .append(304, "Not Modified")
+               .append(305, "Use Proxy")
+               .append(307, "Temporary Redirect")
+               .append(400, "Bad Request")
+               .append(401, "Unauthorized")
+               .append(402, "Payment Required")
+               .append(403, "Forbidden")
+               .append(404, "Not Found")
+               .append(405, "Method Not Allowed")
+               .append(406, "Not Acceptable")
+               .append(407, "Proxy Authentication Required")
+               .append(408, "Request Time-Out")
+               .append(409, "Conflict")
+               .append(410, "Gone")
+               .append(411, "Length Required")
+               .append(412, "Precondition Failed")
+               .append(413, "Request Entity Too Large")
+               .append(414, "Request-URI Too Large")
+               .append(415, "Unsupported Media Type")
+               .append(500, "Internal Server Error")
+               .append(501, "Not Implemented")
+               .append(502, "Bad Gateway")
+               .append(503, "Service Unavailable")
+               .append(504, "Gateway Timeout")
+               .append(505, "HTTP Version Not Supported")
+       ;
+
+       /**
+        * Identical to {@link HttpServletRequest#getPathInfo()} but doesn't 
decode encoded characters.
+        *
+        * @param req The HTTP request
+        * @return The un-decoded path info.
+        */
+       public static String getPathInfoUndecoded(HttpServletRequest req) {
+               String requestURI = req.getRequestURI();
+               String contextPath = req.getContextPath();
+               String servletPath = req.getServletPath();
+               int l = contextPath.length() + servletPath.length();
+               if (requestURI.length() == l)
+                       return null;
+               return requestURI.substring(l);
+       }
+
+       /**
+        * Efficiently trims the path info part from a request URI.
+        *
+        * <p>
+        * The result is the URI of the servlet itself.
+        *
+        * @param requestURI The value returned by {@link 
HttpServletRequest#getRequestURL()}
+        * @param contextPath The value returned by {@link 
HttpServletRequest#getContextPath()}
+        * @param servletPath The value returned by {@link 
HttpServletRequest#getServletPath()}
+        * @return The same StringBuilder with remainder trimmed.
+        */
+       public static StringBuffer trimPathInfo(StringBuffer requestURI, String 
contextPath, String servletPath) {
+               if (servletPath.equals("/"))
+                       servletPath = "";
+               if (contextPath.equals("/"))
+                       contextPath = "";
+
+               try {
+                       // Given URL:  http://hostname:port/servletPath/extra
+                       // We want:    http://hostname:port/servletPath
+                       int sc = 0;
+                       for (int i = 0; i < requestURI.length(); i++) {
+                               char c = requestURI.charAt(i);
+                               if (c == '/') {
+                                       sc++;
+                                       if (sc == 3) {
+                                               if (servletPath.isEmpty()) {
+                                                       requestURI.setLength(i);
+                                                       return requestURI;
+                                               }
+
+                                               // Make sure context path 
follows the authority.
+                                               for (int j = 0; j < 
contextPath.length(); i++, j++)
+                                                       if 
(requestURI.charAt(i) != contextPath.charAt(j))
+                                                               throw new 
Exception("case=1");
+
+                                               // Make sure servlet path 
follows the authority.
+                                               for (int j = 0; j < 
servletPath.length(); i++, j++)
+                                                       if 
(requestURI.charAt(i) != servletPath.charAt(j))
+                                                               throw new 
Exception("case=2");
+
+                                               // Make sure servlet path isn't 
a false match (e.g. /foo2 should not match /foo)
+                                               c = (requestURI.length() == i ? 
'/' : requestURI.charAt(i));
+                                               if (c == '/' || c == '?') {
+                                                       requestURI.setLength(i);
+                                                       return requestURI;
+                                               }
+
+                                               throw new Exception("case=3");
+                                       }
+                               } else if (c == '?') {
+                                       if (sc != 2)
+                                               throw new Exception("case=4");
+                                       if (servletPath.isEmpty()) {
+                                               requestURI.setLength(i);
+                                               return requestURI;
+                                       }
+                                       throw new Exception("case=5");
+                               }
+                       }
+                       if (servletPath.isEmpty())
+                               return requestURI;
+                       throw new Exception("case=6");
+               } catch (Exception e) {
+                       throw new FormattedRuntimeException(e, "Could not find 
servlet path in request URI.  URI=''{0}'', servletPath=''{1}''", requestURI, 
servletPath);
+               }
+       }
+
+       static String[] parseHeader(String s) {
+               int i = s.indexOf(':');
+               if (i == -1)
+                       return null;
+               String name = s.substring(0, 
i).trim().toLowerCase(Locale.ENGLISH);
+               String val = s.substring(i+1).trim();
+               return new String[]{name,val};
+       }
+
+       /**
+        * Parses key/value pairs separated by either : or =
+        */
+       static String[] parseKeyValuePair(String s) {
+               int i = -1;
+               for (int j = 0; j < s.length() && i < 0; j++) {
+                       char c = s.charAt(j);
+                       if (c == '=' || c == ':')
+                               i = j;
+               }
+               if (i == -1)
+                       return null;
+               String name = s.substring(0, i).trim();
+               String val = s.substring(i+1).trim();
+               return new String[]{name,val};
+       }
+
+       static String resolveNewlineSeparatedAnnotation(String[] value, String 
fromParent) {
+               if (value.length == 0)
+                       return fromParent;
+
+               List<String> l = new ArrayList<String>();
+               for (String v : value) {
+                       if (! "INHERIT".equals(v))
+                               l.add(v);
+                       else if (fromParent != null)
+                               l.addAll(Arrays.asList(fromParent));
+               }
+               return join(l, '\n');
+       }
+
+       private static final Pattern INDEXED_LINK_PATTERN = 
Pattern.compile("(?s)(\\S*)\\[(\\d+)\\]\\:(.*)");
+
+       static String[] resolveLinks(String[] links, String[] parentLinks) {
+               if (links.length == 0)
+                       return parentLinks;
+
+               List<String> list = new ArrayList<String>();
+               for (String l : links) {
+                       if ("INHERIT".equals(l))
+                               list.addAll(Arrays.asList(parentLinks));
+                       else if (l.indexOf('[') != -1 && 
INDEXED_LINK_PATTERN.matcher(l).matches()) {
+                                       Matcher lm = 
INDEXED_LINK_PATTERN.matcher(l);
+                                       lm.matches();
+                                       String key = lm.group(1);
+                                       int index = Math.min(list.size(), 
Integer.parseInt(lm.group(2)));
+                                       String remainder = lm.group(3);
+                                       list.add(index, key.isEmpty() ? 
remainder : key + ":" + remainder);
+                       } else {
+                               list.add(l);
+                       }
+               }
+               return list.toArray(new String[list.size()]);
+       }
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,220 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.internal.IOUtils.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.rest.response.*;
+
+/**
+ * Represents the contents of a byte stream file with convenience methods for 
adding HTTP response headers.
+ *
+ * <p>
+ * The purpose of this class is to maintain an in-memory reusable byte array 
of a streamed resource for the fastest
+ * possible streaming.
+ * Therefore, this object is designed to be reused and thread-safe.
+ *
+ * <p>
+ * This class is handled special by the {@link StreamableHandler} class.
+ * This allows these objects to be returned as responses by REST methods.
+ */
+public class StreamResource implements Streamable {
+
+       private final MediaType mediaType;
+       private final byte[][] contents;
+       private final Map<String,String> headers;
+
+       /**
+        * Constructor.
+        *
+        * @param mediaType The resource media type.
+        * @param contents
+        *      The resource contents.
+        *      <br>If multiple contents are specified, the results will be 
concatenated.
+        *      <br>Contents can be any of the following:
+        *      <ul>
+        *              <li><code><jk>byte</jk>[]</code>
+        *              <li><code>InputStream</code>
+        *              <li><code>Reader</code> - Converted to UTF-8 bytes.
+        *              <li><code>File</code>
+        *              <li><code>CharSequence</code> - Converted to UTF-8 
bytes.
+        *              </ul>
+        * @throws IOException
+        */
+       public StreamResource(MediaType mediaType, Object...contents) throws 
IOException {
+               this(mediaType, null, contents);
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param mediaType The resource media type.
+        * @param headers The HTTP response headers for this streamed resource.
+        * @param contents
+        *      The resource contents.
+        *      <br>If multiple contents are specified, the results will be 
concatenated.
+        *      <br>Contents can be any of the following:
+        *      <ul>
+        *              <li><code><jk>byte</jk>[]</code>
+        *              <li><code>InputStream</code>
+        *              <li><code>Reader</code> - Converted to UTF-8 bytes.
+        *              <li><code>File</code>
+        *              <li><code>CharSequence</code> - Converted to UTF-8 
bytes.
+        *              </ul>
+        * @throws IOException
+        */
+       public StreamResource(MediaType mediaType, Map<String,Object> headers, 
Object...contents) throws IOException {
+               this.mediaType = mediaType;
+
+               Map<String,String> m = new LinkedHashMap<String,String>();
+               if (headers != null)
+                       for (Map.Entry<String,Object> e : headers.entrySet())
+                               m.put(e.getKey(), 
StringUtils.toString(e.getValue()));
+               this.headers = Collections.unmodifiableMap(m);
+
+               this.contents = new byte[contents.length][];
+               for (int i = 0; i < contents.length; i++) {
+                       Object c = contents[i];
+                       if (c == null)
+                               this.contents[i] = new byte[0];
+                       else if (c instanceof byte[])
+                               this.contents[i] = (byte[])c;
+                       else if (c instanceof InputStream)
+                               this.contents[i] = readBytes((InputStream)c, 
1024);
+                       else if (c instanceof File)
+                               this.contents[i] = readBytes((File)c);
+                       else if (c instanceof Reader)
+                               this.contents[i] = 
read((Reader)c).getBytes(UTF8);
+                       else if (c instanceof CharSequence)
+                               this.contents[i] = 
((CharSequence)c).toString().getBytes(UTF8);
+                       else
+                               throw new IOException("Invalid class type 
passed to StreamResource: " + c.getClass().getName());
+               }
+       }
+
+       /**
+        * Builder class for constructing {@link StreamResource} objects.
+        */
+       @SuppressWarnings("hiding")
+       public static class Builder {
+               ArrayList<Object> contents = new ArrayList<Object>();
+               MediaType mediaType;
+               Map<String,String> headers = new LinkedHashMap<String,String>();
+
+               /**
+                * Specifies the resource media type string.
+                *
+                * @param mediaType The resource media type string.
+                * @return This object (for method chaining).
+                */
+               public Builder mediaType(String mediaType) {
+                       this.mediaType = MediaType.forString(mediaType);
+                       return this;
+               }
+
+               /**
+                * Specifies the resource media type string.
+                *
+                * @param mediaType The resource media type string.
+                * @return This object (for method chaining).
+                */
+               public Builder mediaType(MediaType mediaType) {
+                       this.mediaType = mediaType;
+                       return this;
+               }
+
+               /**
+                * Specifies the contents for this resource.
+                *
+                * <p>
+                * This method can be called multiple times to add more content.
+                *
+                * @param contents
+                *      The resource contents.
+                *      <br>If multiple contents are specified, the results 
will be concatenated.
+                *      <br>Contents can be any of the following:
+                *      <ul>
+                *              <li><code><jk>byte</jk>[]</code>
+                *              <li><code>InputStream</code>
+                *              <li><code>Reader</code> - Converted to UTF-8 
bytes.
+                *              <li><code>File</code>
+                *              <li><code>CharSequence</code> - Converted to 
UTF-8 bytes.
+                *              </ul>
+                * @return This object (for method chaining).
+                */
+               public Builder contents(Object...contents) {
+                       this.contents.addAll(Arrays.asList(contents));
+                       return this;
+               }
+
+               /**
+                * Specifies an HTTP response header value.
+                *
+                * @param name The HTTP header name.
+                * @param value The HTTP header value.  Will be converted to a 
<code>String</code> using {@link Object#toString()}.
+                * @return This object (for method chaining).
+                */
+               public Builder header(String name, Object value) {
+                       this.headers.put(name, StringUtils.toString(value));
+                       return this;
+               }
+
+               /**
+                * Specifies HTTP response header values.
+                *
+                * @param headers The HTTP headers.  Values will be converted 
to <code>Strings</code> using {@link Object#toString()}.
+                * @return This object (for method chaining).
+                */
+               public Builder headers(Map<String,Object> headers) {
+                       for (Map.Entry<String,Object> e : headers.entrySet())
+                               header(e.getKey(), e.getValue());
+                       return this;
+               }
+
+               /**
+                * Create a new {@link StreamResource} using values in this 
builder.
+                *
+                * @return A new immutable {@link StreamResource} object.
+                * @throws IOException
+                */
+               public StreamResource build() throws IOException {
+                       return new StreamResource(mediaType, headers, 
contents.toArray());
+               }
+       }
+
+       /**
+        * Get the HTTP response headers.
+        *
+        * @return The HTTP response headers.  An unmodifiable map.  Never 
<jk>null</jk>.
+        */
+       public Map<String,String> getHeaders() {
+               return headers;
+       }
+
+       @Override /* Streamable */
+       public void streamTo(OutputStream os) throws IOException {
+               for (byte[] b : contents)
+                       os.write(b);
+       }
+
+       @Override /* Streamable */
+       public MediaType getMediaType() {
+               return mediaType;
+       }
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/UrlPathPattern.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/UrlPathPattern.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/UrlPathPattern.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,200 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.util.*;
+import java.util.regex.*;
+
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * A parsed path pattern constructed from a {@link RestMethod#path()} value.
+ *
+ * <p>
+ * Handles aspects of matching and precedence ordering.
+ */
+public final class UrlPathPattern implements Comparable<UrlPathPattern> {
+
+       private final Pattern pattern;
+       private final String patternString;
+       private final boolean isOnlyDotAll, isDotAll;
+       private final String[] vars;
+
+       /**
+        * Constructor.
+        *
+        * @param patternString The raw pattern string from the {@link 
RestMethod#path()} annotation.
+        */
+       public UrlPathPattern(String patternString) {
+               this.patternString = patternString;
+               Builder b = new Builder(patternString);
+               pattern = b.pattern;
+               isDotAll = b.isDotAll;
+               isOnlyDotAll = b.isOnlyDotAll;
+               vars = b.vars.toArray(new String[b.vars.size()]);
+       }
+
+       @SuppressWarnings("hiding")
+       class Builder {
+               boolean isDotAll, isOnlyDotAll;
+               Pattern pattern;
+               List<String> vars = new LinkedList<String>();
+
+               private Builder(String patternString) {
+                       if (! startsWith(patternString, '/'))
+                               patternString = '/' + patternString;
+                       if (patternString.equals("/*")) {
+                               isOnlyDotAll = true;
+                               return;
+                       }
+                       if (patternString.endsWith("/*"))
+                               isDotAll = true;
+
+                       // Find all {xxx} variables.
+                       Pattern p = Pattern.compile("\\{([^\\}]+)\\}");
+                       Matcher m = p.matcher(patternString);
+                       while (m.find())
+                               vars.add(m.group(1));
+
+                       patternString = 
patternString.replaceAll("\\{[^\\}]+\\}", "([^\\/]+)");
+                       patternString = patternString.replaceAll("\\/\\*$", 
"((?:)|(?:\\/.*))");
+                       pattern = Pattern.compile(patternString);
+               }
+       }
+
+       /**
+        * Returns a non-<jk>null</jk> value if the specified path matches this 
pattern.
+        *
+        * @param path The path to match against.
+        * @return
+        *      An array of values matched against <js>"{var}"</js> variable in 
the pattern, or an empty array if the
+        *      pattern matched but no vars were present, or <jk>null</jk> if 
the specified path didn't match the pattern.
+        */
+       protected String[] match(String path) {
+
+               if (isOnlyDotAll) {
+                       // Remainder always gets leading slash trimmed.
+                       if (path != null)
+                               path = path.substring(1);
+                       return new String[]{path};
+               }
+
+               if (path == null)
+                       return (patternString.equals("/") ? new String[]{} : 
null);
+
+               // If we're not doing a /* match, ignore all trailing slashes.
+               if (! isDotAll)
+                       while (path.length() > 1 && 
path.charAt(path.length()-1) == '/')
+                               path = path.substring(0, path.length()-1);
+
+               Matcher m = pattern.matcher(path);
+               if (! m.matches())
+                       return null;
+
+               int len = m.groupCount();
+               String[] v = new String[len];
+
+               for (int i = 0; i < len; i++) {
+                       if (isDotAll && i == len-1)
+                               v[i] = m.group(i+1).isEmpty() ? null : 
m.group(i+1).substring(1);
+                       else
+                       v[i] = urlDecode(m.group(i+1));
+               }
+
+               return v;
+       }
+
+       /**
+        * Comparator for this object.
+        *
+        * <p>
+        * The comparator is designed to order URL pattern from most-specific 
to least-specific.
+        * For example, the following patterns would be ordered as follows:
+        * <ol>
+        *      <li><code>/foo/bar</code>
+        *      <li><code>/foo/bar/*</code>
+        *      <li><code>/foo/{id}/bar</code>
+        *      <li><code>/foo/{id}/bar/*</code>
+        *      <li><code>/foo/{id}</code>
+        *      <li><code>/foo/{id}/*</code>
+        *      <li><code>/foo</code>
+        *      <li><code>/foo/*</code>
+        * </ol>
+        */
+       @Override /* Comparable */
+       public int compareTo(UrlPathPattern o) {
+               String s1 = patternString.replaceAll("\\{[^\\}]+\\}", 
".").replaceAll("\\w+", "X").replaceAll("\\.", "W");
+               String s2 = o.patternString.replaceAll("\\{[^\\}]+\\}", 
".").replaceAll("\\w+", "X").replaceAll("\\.", "W");
+               if (s1.isEmpty())
+                       s1 = "+";
+               if (s2.isEmpty())
+                       s2 = "+";
+               if (! s1.endsWith("/*"))
+                       s1 = s1 + "/W";
+               if (! s2.endsWith("/*"))
+                       s2 = s2 + "/W";
+               int c = s2.compareTo(s1);
+               if (c == 0)
+                       return o.toRegEx().compareTo(toRegEx());
+               return c;
+       }
+
+       @Override /* Object */
+       public boolean equals(Object o) {
+               if (! (o instanceof UrlPathPattern))
+                       return false;
+               return (compareTo((UrlPathPattern)o) == 0);
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return super.hashCode();
+       }
+
+       @Override /* Object */
+       public String toString() {
+               return patternString;
+       }
+
+       /**
+        * Returns this path pattern as the compiled regular expression.
+        *
+        * <p>
+        * Useful for debugging.
+        *
+        * @return The path pattern.
+        */
+       public String toRegEx() {
+               return isOnlyDotAll ? "*" : pattern.pattern();
+       }
+
+       /**
+        * Bean property getter:  <property>vars</property>.
+        *
+        * @return The value of the <property>vars</property> property on this 
bean, or <jk>null</jk> if it is not set.
+        */
+       public String[] getVars() {
+               return vars;
+       }
+
+       /**
+        * Bean property getter:  <property>patternString</property>.
+        *
+        * @return The value of the <property>patternString</property> property 
on this bean, or <jk>null</jk> if it is not set.
+        */
+       public String getPatternString() {
+               return patternString;
+       }
+}
\ No newline at end of file

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/UrlPathPattern.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,57 @@
+// 
***************************************************************************************************************************
+// * 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.rest.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.io.*;
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} 
annotated method to identify it as the HTTP
+ * request body converted to a POJO.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> doPostPerson(RestRequest req, RestResponse res, 
<ja>@Body</ja> Person person) {
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * This is functionally equivalent to the following code...
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> doPostPerson(RestRequest req, RestResponse res) {
+ *             Person person = req.getBody().asType(Person.<jk>class</jk>);
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * {@link Reader Readers} and {@link InputStream InputStreams} can also be 
specified as content parameters.
+ * When specified, any registered parsers are bypassed.
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> 
doPostPerson(<ja>@Header</ja>(<js>"Content-Type"</js>) String mediaType, 
<ja>@Body</ja> InputStream input) {
+ *             ...
+ *     }
+ * </p>
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Body {}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,118 @@
+// 
***************************************************************************************************************************
+// * 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.rest.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.rest.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} 
annotated method to identify it as a form post
+ * entry converted to a POJO.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> doPost(RestRequest req, RestResponse res,
+ *                             <ja>@FormData</ja>(<js>"p1"</js>) <jk>int</jk> 
p1, <ja>@FormData</ja>(<js>"p2"</js>) String p2, 
<ja>@FormData</ja>(<js>"p3"</js>) UUID p3) {
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * This is functionally equivalent to the following code...
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> doPost(RestRequest req, RestResponse res) {
+ *             <jk>int</jk> p1 = req.getFormData(<jk>int</jk>.<jk>class</jk>, 
<js>"p1"</js>, 0);
+ *             String p2 = req.getFormData(String.<jk>class</jk>, 
<js>"p2"</js>);
+ *             UUID p3 = req.getFormData(UUID.<jk>class</jk>, <js>"p3"</js>);
+ *             ...
+ *     }
+ * </p>
+ *
+ * <h6 class='topic'>Important note concerning FORM posts</h6>
+ *
+ * This annotation should not be combined with the {@link Body @Body} 
annotation or {@link RestRequest#getBody()} method
+ * for <code>application/x-www-form-urlencoded POST</code> posts, since it 
will trigger the underlying servlet
+ * API to parse the body content as key-value pairs resulting in empty content.
+ *
+ * <p>
+ * The {@link Query @Query} annotation can be used to retrieve a URL parameter 
in the URL string without triggering the
+ * servlet to drain the body content.
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface FormData {
+
+       /**
+        * FORM parameter name.
+        */
+       String name() default "";
+
+       /**
+        * A synonym for {@link #name()}.
+        *
+        * <p>
+        * Allows you to use shortened notation if you're only specifying the 
name.
+        */
+       String value() default "";
+
+       /**
+        * Specify <jk>true</jk> if using multi-part parameters to represent 
collections and arrays.
+        *
+        * <p>
+        * Normally, we expect single parameters to be specified in UON 
notation for representing collections of values
+        * (e.g. <js>"key=(1,2,3)"</js>.
+        * This annotation allows the use of multi-part parameters to represent 
collections (e.g.
+        * <js>"key=1&amp;key=2&amp;key=3"</js>.
+        *
+        * <p>
+        * This setting should only be applied to Java parameters of type array 
or Collection.
+        */
+       boolean multipart() default false;
+
+       /**
+        * The expected format of the request parameter.
+        *
+        * <p>
+        * Possible values:
+        * <ul class='spaced-list'>
+        *      <li>
+        *              <js>"UON"</js> - URL-Encoded Object Notation.
+        *              <br>This notation allows for request parameters to 
contain arbitrarily complex POJOs.
+        *      <li>
+        *              <js>"PLAIN"</js> - Plain text.
+        *              <br>This treats request parameters as plain text.
+        *              <br>Only POJOs directly convertible from <l>Strings</l> 
can be represented in parameters when using this mode.
+        *      <li>
+        *              <js>"INHERIT"</js> (default) - Inherit from the {@link 
RestContext#REST_paramFormat} property on the
+        *              servlet method or class.
+        * </ul>
+        *
+        * <p>
+        * Note that the parameter value <js>"(foo)"</js> is interpreted as 
<js>"(foo)"</js> when using plain mode, but
+        * <js>"foo"</js> when using UON mode.
+        */
+       String format() default "INHERIT";
+
+       /**
+        * The default value for this form-data parameter if it's not present 
in the request.
+        */
+       String def() default "";
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/FormData.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasFormData.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasFormData.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasFormData.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,105 @@
+// 
***************************************************************************************************************************
+// * 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.rest.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.rest.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} 
annotated method to identify whether or not
+ * the request has the specified multipart form POST parameter.
+ *
+ * <p>
+ * Note that this can be used to detect the existence of a parameter when it's 
not set to a particular value.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> doPost(<ja>@HasFormData</ja>(<js>"p1"</js>) 
<jk>boolean</jk> p1) {
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * This is functionally equivalent to the following code...
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"POST"</js>)
+ *     <jk>public void</jk> doPost(RestRequest req) {
+ *             <jk>boolean</jk> p1 = req.hasFormData(<js>"p1"</js>);
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * The following table shows the behavioral differences between 
<code>@HasFormData</code> and <code>@FormData</code>...
+ * <table class='styled'>
+ *     <tr>
+ *             <th><code>Body content</code></th>
+ *             <th><code><ja>@HasFormData</ja>(<js>"a"</js>)</code></th>
+ *             <th><code><ja>@FormData</ja>(<js>"a"</js>)</code></th>
+ *     </tr>
+ *     <tr>
+ *             <td><code>a=foo</code></td>
+ *             <td><jk>true</jk></td>
+ *             <td><js>"foo"</js></td>
+ *     </tr>
+ *     <tr>
+ *             <td><code>a=</code></td>
+ *             <td><jk>true</jk></td>
+ *             <td><js>""</js></td>
+ *     </tr>
+ *     <tr>
+ *             <td><code>a</code></td>
+ *             <td><jk>true</jk></td>
+ *             <td><jk>null</jk></td>
+ *     </tr>
+ *     <tr>
+ *             <td><code>b=foo</code></td>
+ *             <td><jk>false</jk></td>
+ *             <td><jk>null</jk></td>
+ *     </tr>
+ * </table>
+ *
+ * <h6 class='topic'>Important note concerning FORM posts</h6>
+ *
+ * This annotation should not be combined with the {@link Body @Body} 
annotation or {@link RestRequest#getBody()} method
+ * for <code>application/x-www-form-urlencoded POST</code> posts, since it 
will trigger the underlying servlet API to
+ * parse the body content as key-value pairs, resulting in empty content.
+ *
+ * <p>
+ * The {@link HasQuery @HasQuery} annotation can be used to check for the 
existing of a URL parameter in the URL string
+ * without triggering the servlet to drain the body content.
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface HasFormData {
+
+       /**
+        * FORM parameter name.
+        */
+       String name() default "";
+
+       /**
+        * A synonym for {@link #name()}.
+        *
+        * <p>
+        * Allows you to use shortened notation if you're only specifying the 
name.
+        */
+       String value() default "";
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasFormData.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasQuery.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasQuery.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasQuery.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,68 @@
+// 
***************************************************************************************************************************
+// * 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.rest.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.rest.*;
+
+/**
+ * Identical to {@link HasFormData @HasFormData}, but only checks the existing 
of the parameter in the URL string, not
+ * URL-encoded form posts.
+ *
+ * <p>
+ * Unlike {@link HasFormData @HasFormData}, using this annotation does not 
result in the servlet reading the contents
+ * of URL-encoded form posts.
+ * Therefore, this annotation can be used in conjunction with the {@link Body 
@Body} annotation or
+ * {@link RestRequest#getBody()} method for 
<code>application/x-www-form-urlencoded POST</code> calls.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ *     <jk>public void</jk> doPost(<ja>@HasQuery</ja>(<js>"p1"</js>) 
<jk>boolean</jk> p1, <ja>@Body</ja> Bean myBean) {
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * This is functionally equivalent to the following code...
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ *     <jk>public void</jk> doGet(RestRequest req) {
+ *             <jk>boolean</jk> p1 = req.hasQueryParameter(<js>"p1"</js>);
+ *             ...
+ *     }
+ * </p>
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface HasQuery {
+
+       /**
+        * URL query parameter name.
+        */
+       String name() default "";
+
+       /**
+        * A synonym for {@link #name()}.
+        *
+        * <p>
+        * Allows you to use shortened notation if you're only specifying the 
name.
+        */
+       String value() default "";
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HasQuery.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
==============================================================================
--- 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
 (added)
+++ 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
 Fri Sep  8 23:25:34 2017
@@ -0,0 +1,65 @@
+// 
***************************************************************************************************************************
+// * 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.rest.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation that can be applied to a parameter of a {@link RestMethod} 
annotated method to identify it as a HTTP
+ * request header converted to a POJO.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ *     <jk>public void</jk> doGet(RestRequest req, RestResponse res, 
<ja>@Header</ja>(<js>"ETag"</js>) UUID etag) {
+ *             ...
+ *     }
+ * </p>
+ *
+ * <p>
+ * This is functionally equivalent to the following code...
+ * <p class='bcode'>
+ *     <ja>@RestMethod</ja>(name=<js>"GET"</js>)
+ *     <jk>public void</jk> doPostPerson(RestRequest req, RestResponse res) {
+ *             UUID etag = req.getHeader(UUID.<jk>class</jk>, "ETag");
+ *             ...
+ *     }
+ * </p>
+ */
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Header {
+
+       /**
+        * HTTP header name.
+        */
+       String name() default "";
+
+       /**
+        * A synonym for {@link #name()}.
+        *
+        * <p>
+        * Allows you to use shortened notation if you're only specifying the 
name.
+        */
+       String value() default "";
+
+       /**
+        * The default value for this header if it's not present in the request.
+        */
+       String def() default "";
+}

Propchange: 
release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Header.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to