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&key=2&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