http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Response.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Response.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Response.java new file mode 100755 index 0000000..ee8d32c --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Response.java @@ -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.server.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation used in conjunction with {@link RestMethod#responses()} to identify possible responses by the method. + * + * <h6 class='topic'>Example</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"*"</js>, + * responses={ + * <ja>@Response</ja>(value=200,description=<js>"Everything was great."</js>), + * <ja>@Response</ja>(value=404,description=<js>"File was not found."</js>) + * <ja>@Response</ja>(500), + * } + * ) + * <jk>public void</jk> doAnything(RestRequest req, RestResponse res, <ja>@Method</ja> String method) { + * ... + * } + * </p> + * + * @author James Bognar (james.bog...@salesforce.com) + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Response { + + /** + * HTTP response code. + */ + int value(); + + /** + * Optional description. + * <p> + * The default value pulls the description from the <code>description</code> entry in the servlet resource bundle. + * (e.g. <js>"myMethod.res.[code] = foo"</js> or <js>"MyServlet.myMethod.res.[code] = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + */ + String description() default ""; + + /** + * Optional response variables. + * <p> + * Response variables can also be defined in the servlet resource bundle. + * (e.g. <js>"myMethod.res.[code].[category].[name] = foo"</js> or <js>"MyServlet.myMethod.res.[code].[category].[name] = foo"</js>). + */ + Var[] output() default {}; +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestMethod.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestMethod.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestMethod.java new file mode 100755 index 0000000..0df53ee --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestMethod.java @@ -0,0 +1,438 @@ +/*************************************************************************************************************************** + * 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.server.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.encoders.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.server.*; + +/** + * Identifies a REST Java method on a {@link RestServlet} implementation class. + * <p> + * Refer to {@link org.apache.juneau.server} doc for information on using this class. + * + * @author James Bognar (james.bog...@salesforce.com) + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +@Inherited +public @interface RestMethod { + + /** + * REST method name. + * <p> + * Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>. + * <p> + * Can also be a non-HTTP-standard name that is passed in through a <code>&method=methodName</code> URL parameter. + * <p> + * Method names are case-insensitive (always folded to upper-case). + * <p> + * If a method name is not specified, then the method name is determined based on the Java method name.<br> + * For example, if the method is <code>doPost(...)</code>, then the method name is automatically detected as <js>"POST"</js>. + + */ + String name() default ""; + + /** + * Optional path pattern for the specified method. + * <p> + * Appending <js>"/*"</js> to the end of the path pattern will make it match any remainder too.<br> + * Not appending <js>"/*"</js> to the end of the pattern will cause a 404 (Not found) error to occur + * if the exact pattern is not found. + */ + String path() default "/*"; + + /** + * URL path pattern priority. + * <p> + * To force path patterns to be checked before other path patterns, use a higher priority number. + * <p> + * By default, it's <code>0</code>, which means it will use an internal heuristic to + * determine a best match. + */ + int priority() default 0; + + /** + * Method guards. + * <p> + * Associates one or more {@link RestGuard RestGuards} with a method call. + * These guards get called immediately before execution of the REST method. + * <p> + * Typically, guards will be used for permissions checking on the user making the request, + * but it can also be used for other purposes like pre-call validation of a request. + */ + Class<? extends RestGuard>[] guards() default {}; + + /** + * Method response converters. + * <p> + * Associates one or more {@link RestConverter RestConverters} with a method call. + * These converters get called immediately after execution of the REST method in the same + * order specified in the annotation. + * <p> + * Can be used for performing post-processing on the response object before serialization. + * <p> + * Default converters are available in the {@link org.apache.juneau.server.converters} package. + */ + Class<? extends RestConverter>[] converters() default {}; + + /** + * Method matchers. + * <p> + * Associates one more more {@link RestMatcher RestMatchers} with this method. + * <p> + * Matchers are used to allow multiple Java methods to handle requests assigned to the same + * URL path pattern, but differing based on some request attribute, such as a specific header value. + * <p> + * See {@link RestMatcher} for details. + */ + Class<? extends RestMatcher>[] matchers() default {}; + + /** + * Overrides the list of serializers assigned at the method level. + * <p> + * Use this annotation when the list of serializers assigned to a method differs from the list of serializers assigned at the servlet level. + * <p> + * To append to the list of serializers assigned at the servlet level, use <code>serializersInherit=<jsf>SERIALIZERS</jsf></code>. + * + * <p class='bcode'> + * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { + * + * <ja>@RestMethod</ja>( + * name=<js>"GET"</js>, + * path=<js>"/foo"</js>, + * serializers=MySpecialSerializer.<jk>class</jk>, + * serializersInherit=<jsf>SERIALIZERS</jsf> + * ) + * <jk>public</jk> Object doGetWithSpecialAcceptType() { + * <jc>// Handle request for special Accept type</jc> + * } + * } + * </p> + */ + Class<? extends Serializer>[] serializers() default {}; + + /** + * Used in conjunction with {@link #serializers()} to identify what class-level settings are inherited by the method serializer group. + * <p> + * Possible values: + * </p> + * <ul> + * <li>{@link Inherit#SERIALIZERS} - Inherit class-level serializers. + * <li>{@link Inherit#PROPERTIES} - Inherit class-level properties. + * <li>{@link Inherit#TRANSFORMS} - Inherit class-level transforms. + * </ul> + * <p> + * For example, to inherit all serializers, properties, and transforms from the servlet class: + * </p> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * path=<js>"/foo"</js>, + * serializers=MySpecialSerializer.<jk>class</jk>, + * serializersInherit={<jsf>SERIALIZERS</jsf>,<jsf>PROPERTIES</jsf>,<jsf>TRANSFORMS</jsf>} + * ) + * </p> + */ + Inherit[] serializersInherit() default {}; + + /** + * Overrides the list of parsers assigned at the method level. + * <p> + * Use this annotation when the list of parsers assigned to a method differs from the list of parsers assigned at the servlet level. + * <p> + * To append to the list of serializers assigned at the servlet level, use <code>serializersInherit=<jsf>SERIALIZERS</jsf></code>. + * + * <p class='bcode'> + * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { + * + * <ja>@RestMethod</ja>( + * name=<js>"PUT"</js>, + * path=<js>"/foo"</js>, + * parsers=MySpecialParser.<jk>class</jk>, + * parsersInherit=<jsf>PARSERS</jsf> + * ) + * <jk>public</jk> Object doGetWithSpecialAcceptType() { + * <jc>// Handle request for special Accept type</jc> + * } + * } + * </p> + */ + Class<? extends Parser>[] parsers() default {}; + + /** + * Used in conjunction with {@link #parsers()} to identify what class-level settings are inherited by the method parser group. + * <p> + * Possible values: + * <ul> + * <li>{@link Inherit#PARSERS} - Inherit class-level parsers. + * <li>{@link Inherit#PROPERTIES} - Inherit class-level properties. + * <li>{@link Inherit#TRANSFORMS} - Inherit class-level transforms. + * </ul> + * <p> + * For example, to inherit all parsers, properties, and transforms from the servlet class: + * </p> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * path=<js>"/foo"</js>, + * parsers=MySpecialParser.<jk>class</jk>, + * parsersInherit={<jsf>PARSERS</jsf>,<jsf>PROPERTIES</jsf>,<jsf>TRANSFORMS</jsf>} + * ) + * </p> + */ + Inherit[] parsersInherit() default {}; + + /** + * Appends to the list of {@link Encoder encoders} specified on the servlet. + * <p> + * Use this annotation when the list of encoders assigned to a method differs from the list of encoders assigned at the servlet level. + * <p> + * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses. + * + * <p class='bcode'> + * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { + * + * <ja>@RestMethod</ja>( + * name=<js>"PUT"</js>, + * path=<js>"/foo"</js>, + * encoders={GzipEncoder.<jk>class</jk>} + * ) + * <jk>public</jk> Object doGetWithSpecialEncoding() { + * <jc>// Handle request with special encoding</jc> + * } + * } + * </p> + * + * If you want to OVERRIDE the set of encoders specified by the servlet, combine this annotation with <code><ja>@RestMethod</ja>(inheritEncoders=<jk>false</jk>)</code>. + */ + Class<? extends Encoder>[] encoders() default {}; + + /** + * Specifies whether the method should inherit encoders from the servlet. + */ + boolean inheritEncoders() default true; + + /** + * Same as {@link RestResource#properties()}, except defines property values by default when this method is called. + * <p> + * This is equivalent to simply calling <code>res.addProperties()</code> in the Java method, but is provided for convenience. + */ + Property[] properties() default {}; + + /** + * Appends the specified transforms to all serializers and parsers used by this method. + */ + Class<?>[] transforms() default {}; + + /** + * Possible HTTP response codes from this method. + * <p> + * This annotation is provided for documentation purposes. + * It is used in conjunction with the following NLS resource bundle keys to populate options pages: + * <ul class='spaced-list'> + * <li><js>"(className.?)[javaMethodName].res.[rc]"</js> - Response description (defaults to HTTP status message). + * e.g. <js>"MyClass.myMethod.res.404 = Sorry...I couldn't find that."</js> or <js>"myMethod.res.404 = Sorry...I couldn't find that."</js> + * <li><js>"(className.?)[javaMethodName].res.[rc].[varCategory].[varName]"</js> - Response variable . + * e.g. <js>"MyClass.myMethod.res.302.[header].[Location] = Set to the location where the thing can be found."</js> or <js>"myMethod.res.302.[header].[Location] = Set to the location where the thing can be found."</js> + * </ul> + * <p> + * Note that you can still define the keys in the resource bundle and not use this annotation. + * However, the annotation is provided if you just want the OPTIONS page to show the possible status codes with + * default HTTP status messages. + */ + int[] rc() default {}; + + /** + * Specifies default values for request headers. + * <p> + * Strings are of the format <js>"Header-Name: header-value"</js>. + * <p> + * Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request. + * <p> + * The most useful reason for this annotation is to provide a default <code>Accept</code> header when one is not specified + * so that a particular default {@link Serializer} is picked. + * <p> + * Only one header value can be specified per entry (i.e. it's not a delimited list of header entries). + * <p> + * Header values specified at the method level override header values specified at the servlet level. + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jc>// Assume "text/json" Accept value when Accept not specified</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>, defaultRequestHeaders={<js>"Accept: text/json"</js>}) + * <jk>public</jk> String doGet() { + * ... + * } + * </p> + * </dd> + * </dl> + */ + String[] defaultRequestHeaders() default {}; + + /** + * Optional description. + * <p> + * This description is used in the following locations: + * <ul class='spaced-list'> + * <li>The value returned by {@link RestRequest#getMethodDescription()}. + * <li>The <js>"$R{methodDescription}"</js> variable. + * <li>The description of the method in the OPTIONS page. + * </ul> + * <p> + * The default value pulls the description from the <code>(className.?)[javaMethodName]</code> entry in the servlet resource bundle. + * (e.g. <js>"MyClass.myMethod = foo"</js> or <js>"myMethod = foo"</js>). + * <p> + * This field value can contain variables (e.g. "$L{my.localized.variable}"). + */ + String description() default ""; + + /** + * Optional input description. + * <p> + * This annotation is provided for documentation purposes and is used to populate the method <js>"input"</js> column + * on the OPTIONS page. + * <p> + * Example: + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"POST"</js>, path=<js>"/{a}"</js>, + * description=<js>"This is my method."</js>, + * input={ + * <ja>@Var</ja>(category=<js>"attr"</js>, name=<js>"a"</js>, description=<js>"The 'a' attribute"</js>), + * <ja>@Var</ja>(category=<js>"param"</js>, name=<js>"b"</js>, description=<js>"The 'b' parameter"</js>), + * <ja>@Var</ja>(category=<js>"content"</js>, description=<js>"The HTTP content"</js>), + * <ja>@Var</ja>(category=<js>"header"</js>, name=<js>"D"</js>, description=<js>"The 'D' header"</js>), + * <ja>@Var</ja>(category=<js>"foo"</js>, name=<js>"bar"</js>, description=<js>"An arbitrary category"</js>) + * } + * ) + * </p> + * This is functionally equivalent to specifying the following keys in the resource bundle for the class, except in this case + * the strings are internationalized. + * <p class='bcode'> + * <jk>MyClass.myMethod</jk> = <js>This is my method.</js> + * <jk>MyClass.myMethod.req.attr.a</jk> = <js>The 'a' attribute</js> + * <jk>MyClass.myMethod.req.param.b</jk> = <js>The 'b' parameter</js> + * <jk>MyClass.myMethod.req.content</jk> = <js>The HTTP content</js> + * <jk>MyClass.myMethod.req.header.d</jk> = <js>The 'D' header</js> + * <jk>MyClass.myMethod.req.foo.bar</jk> = <js>An arbitrary category</js> + * <p> + * As a general rule, use annotations when you don't care about internationalization (i.e. you only want to support English), + * and use resource bundles if you need to support localization. + * <p> + * These annotations can contain variables (e.g. "$L{my.localized.variable}"). + */ + Var[] input() default {}; + + + /** + * Optional output description. + * <p> + * This annotation is provided for documentation purposes and is used to populate the method <js>"responses"</js> column + * on the OPTIONS page. + * <p> + * Example: + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"GET"</js>, path=<js>"/"</js>, + * responses={ + * <ja>@Response</ja>(200), + * <ja>@Response</ja>( + * value=302, + * description=<js>"Thing wasn't found here"</js>, + * output={ + * <ja>@Var</ja>(category=<js>"header"</js>, name=<js>"Location"</js>, description=<js>"The place to find the thing"</js>) + * } + * ) + * } + * ) + * </p> + * This is functionally equivalent to specifying the following keys in the resource bundle for the class, except in this case + * the strings are internationalized. + * <p class='bcode'> + * <jk>MyClass.myMethod.res.200</jk> = <js>OK</js> + * <jk>MyClass.myMethod.res.302</jk> = <js>Thing wasn't found here</js> + * <jk>MyClass.myMethod.res.302.header.Location</jk> = <js>The place to find the thing</js> + * <p> + * As a general rule, use annotations when you don't care about internationalization (i.e. you only want to support English), + * and use resource bundles if you need to support localization. + * <p> + * These annotations can contain variables (e.g. "$L{my.localized.variable}"). + */ + Response[] responses() default {}; + + /** + * Specifies whether this method can be called based on the client version. + * <p> + * The client version is identified via the HTTP request header identified by {@link RestResource#clientVersionHeader()} which + * by default is <js>"X-Client-Version"</js>. + * <p> + * This is a specialized kind of {@link RestMatcher} that allows you to invoke different Java methods for the same method/path based + * on the client version. + * <p> + * The format of the client version range is similar to that of OSGi versions. + * <p> + * In the following example, the Java methods are mapped to the same HTTP method and URL <js>"/foobar"</js>. + * <p class='bcode'> + * <jc>// Call this method if X-Client-Version is at least 2.0. + * // Note that this also matches 2.0.1.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>) + * <jk>public</jk> Object method1() { + * ... + * } + * + * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>) + * <jk>public</jk> Object method2() { + * ... + * } + * + * <jc>// Call this method if X-Client-Version is less than 1.1.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>) + * <jk>public</jk> Object method3() { + * ... + * } + * </p> + * <p> + * It's common to combine the client version with transforms that will convert new POJOs into older POJOs for backwards compatability. + * <p class='bcode'> + * <jc>// Call this method if X-Client-Version is at least 2.0.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>) + * <jk>public</jk> NewPojo newMethod() { + * ... + * } + * + * <jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>, transforms={NewToOldPojoTransform.<jk>class</jk>}) + * <jk>public</jk> NewPojo oldMethod() { + * <jk>return</jk> newMethod() + * } + * <p> + * Note that in the previous example, we're returning the exact same POJO, but using a transform to convert it into an older form. + * The old method could also just return back a completely different object. + * The range can be any of the following: + * <ul> + * <li><js>"[0,1.0)"</js> = Less than 1.0. 1.0 and 1.0.0 does not match. + * <li><js>"[0,1.0]"</js> = Less than or equal to 1.0. Note that 1.0.1 will match. + * <li><js>"1.0"</js> = At least 1.0. 1.0 and 2.0 will match. + * </ul> + */ + String clientVersion() default ""; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestResource.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestResource.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestResource.java new file mode 100755 index 0000000..682b898 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/RestResource.java @@ -0,0 +1,445 @@ +/*************************************************************************************************************************** + * 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.server.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import javax.servlet.http.*; + +import org.apache.juneau.*; +import org.apache.juneau.encoders.*; +import org.apache.juneau.jena.*; +import org.apache.juneau.json.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.server.*; +import org.apache.juneau.transform.*; +import org.apache.juneau.utils.*; +import org.apache.juneau.xml.*; + +/** + * Optionally used to associate metadata on an instance of {@link RestServlet}. + * <p> + * Refer to {@link org.apache.juneau.server} doc for information on using this class. + * + * @author James Bognar (james.bog...@salesforce.com) + */ +@Documented +@Target(TYPE) +@Retention(RUNTIME) +@Inherited +public @interface RestResource { + + /** + * Identifies the location of the resource bundle for this class. + * <p> + * This annotation is used to provide localized messages for the following methods: + * <ul> + * <li>{@link RestServlet#getMessage(java.util.Locale, String, Object...)} + * <li>{@link RestServlet#getMethodDescriptions(RestRequest)} + * <li>{@link RestServlet#getLabel(RestRequest)} + * <li>{@link RestServlet#getDescription(RestRequest)} + * </ul> + * <p> + * Refer to the {@link MessageBundle} class for a description of the message key formats + * used in the properties file. + * <p> + * The value can be a relative path like <js>"nls/Messages"</js>, indicating to look for the + * resource bundle <js>"com.ibm.sample.nls.Messages"</js> if the resource class + * is in <js>"com.ibm.sample"</js>, or it can be an absolute path, like <js>"com.ibm.sample.nls.Messages"</js> + */ + String messages() default ""; + + /** + * Class-level guards. + * <p> + * Associates one or more {@link RestGuard RestGuards} with all REST methods defined + * in this class. + * These guards get called immediately before execution of any REST method in this class. + * <p> + * Typically, guards will be used for permissions checking on the user making the request, + * but it can also be used for other purposes like pre-call validation of a request. + */ + Class<? extends RestGuard>[] guards() default {}; + + /** + * Class-level converters. + * <p> + * Associates one or more {@link RestConverter converters} with a resource class. + * These converters get called immediately after execution of the REST method in the same + * order specified in the annotation. + * <p> + * Can be used for performing post-processing on the response object before serialization. + * <p> + * Default converter implementations are provided in the {@link org.apache.juneau.server.converters} package. + */ + Class<? extends RestConverter>[] converters() default {}; + + /** + * Class-level POJO filters. + * <p> + * Shortcut to add POJO filters to the bean contexts of the objects returned by the following methods: + * <ul> + * <li>{@link RestServlet#getBeanContext()} + * <li>{@link RestServlet#getSerializers()} + * <li>{@link RestServlet#getParsers()} + * </ul> + * <p> + * If the specified class is an instance of {@link Transform}, then that filter is added. + * Any other classes are wrapped in a {@link BeanTransform} to indicate that subclasses should + * be treated as the specified class type. + */ + Class<?>[] transforms() default {}; + + /** + * Class-level properties. + * <p> + * Shortcut for specifying class-level properties on this servlet to the objects returned by the following methods: + * <ul> + * <li>{@link RestServlet#getBeanContext()} + * <li>{@link RestServlet#getSerializers()} + * <li>{@link RestServlet#getParsers()} + * </ul> + * <p> + * Any of the following property names can be specified: + * <ul> + * <li>{@link RestServletContext} + * <li>{@link BeanContext} + * <li>{@link SerializerContext} + * <li>{@link ParserContext} + * <li>{@link JsonSerializerContext} + * <li>{@link RdfSerializerContext} + * <li>{@link RdfParserContext} + * <li>{@link RdfCommonContext} + * <li>{@link XmlSerializerContext} + * <li>{@link XmlParserContext} + * </ul> + * <p> + * Property values will be converted to the appropriate type. + * <p> + * In some cases, properties can be overridden at runtime through the {@link RestResponse#setProperty(String, Object)} method + * or through a {@link Properties @Properties} annotated method parameter. + */ + Property[] properties() default {}; + + /** + * Specifies a list of {@link Serializer} classes to add to the list of serializers available for this servlet. + * <p> + * This annotation can only be used on {@link Serializer} classes that have no-arg constructors. + */ + Class<? extends Serializer>[] serializers() default {}; + + /** + * Specifies a list of {@link Parser} classes to add to the list of parsers available for this servlet. + * <p> + * This annotation can only be used on {@link Parser} classes that have no-arg constructors. + */ + Class<? extends Parser>[] parsers() default {}; + + /** + * Specifies a list of {@link ResponseHandler} classes that know how to convert POJOs returned + * by REST methods or set via {@link RestResponse#setOutput(Object)} into appropriate + * HTTP responses. + * See {@link ResponseHandler} for details. + */ + Class<? extends ResponseHandler>[] responseHandlers() default {}; + + /** + * Specifies a list of {@link Encoder} to associate with this servlet. + * <p> + * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses. + * <p> + * This annotation can only be used on {@link Encoder} classes that have no-arg constructors. + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jc>// Servlet with automated support for GZIP compression</jc> + * <ja>@RestResource</ja>(encoders={GzipEncoder.<jk>class</jk>}) + * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + * ... + * } + * </p> + * </dd> + * </dl> + */ + Class<? extends Encoder>[] encoders() default {}; + + /** + * Specifies default values for request headers. + * <p> + * Strings are of the format <js>"Header-Name: header-value"</js>. + * <p> + * Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request. + * <p> + * The most useful reason for this annotation is to provide a default <code>Accept</code> header when one is not specified + * so that a particular default {@link Serializer} is picked. + * <p> + * Only one header value can be specified per entry (i.e. it's not a delimited list of header entries). + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jc>// Assume "text/json" Accept value when Accept not specified</jc> + * <ja>@RestResource</ja>(defaultRequestHeaders={<js>"Accept: text/json"</js>}) + * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + * ... + * } + * </p> + * </dd> + * </dl> + */ + String[] defaultRequestHeaders() default {}; + + /** + * Specifies default values for response headers. + * <p> + * Strings are of the format <js>"Header-Name: header-value"</js>. + * <p> + * This is equivalent to calling {@link RestResponse#setHeader(String, String)} programmatically in each of the Java methods. + * <p> + * The header value will not be set if the header value has already been specified (hence the 'default' in the name). + * <p> + * Only one header value can be specified per entry (i.e. it's not a delimited list of header entries). + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jc>// Add a version header attribute to all responses</jc> + * <ja>@RestResource</ja>(defaultResponseHeaders={<js>"X-Version: 1.0"</js>}) + * <jk>public</jk> MyRestServlet <jk>extends</jk> RestServlet { + * ... + * } + * </p> + * </dd> + * </dl> + */ + String[] defaultResponseHeaders() default {}; + + /** + * Defines children of this resource. + * <p> + * A REST child resource is simply another servlet that is initialized as part of the parent + * resource and has a servlet path directly under the parent servlet path. + * The main advantage to defining servlets as REST children is that you do not need + * to define them in the <code>web.xml</code> file of the web application. + * This can cut down on the number of entries that show up in the <code>web.xml</code> file + * if you are defining large numbers of servlets. + * <p> + * Child resources must specify a value for {@link #path()} that identifies the subpath of the + * child resource relative to the parent path. + * <p> + * It should be noted that servlets can be nested arbitrarily deep using this technique (i.e. children can also have children). + * + * <dl> + * <dt>Servlet initialization:</dt> + * <dd> + * <p> + * A child resource will be initialized immediately after the parent servlet is initialized. The child resource + * receives the same servlet config as the parent resource. This allows configuration information such as + * servlet initialization parameters to filter to child resources. + * </p> + * </dd> + * <dt>Runtime behavior:</dt> + * <dd> + * <p> + * As a rule, methods defined on the <code>HttpServletRequest</code> object will behave as if + * the child servlet were deployed as a top-level resource under the child's servlet path. + * For example, the <code>getServletPath()</code> and <code>getPathInfo()</code> methods on the + * <code>HttpServletRequest</code> object will behave as if the child resource were deployed + * using the child's servlet path. + * Therefore, the runtime behavior should be equivalent to deploying the child servlet in + * the <code>web.xml</code> file of the web application. + * </p> + * </dd> + * </dl> + */ + Class<?>[] children() default {}; + + /** + * Identifies the URL subpath relative to the parent resource. + * <p> + * Typically, this annotation is only applicable to resources defined as children through the {@link #children()} + * annotation. However, it may be used in other ways (e.g. defining paths for top-level resources in microservices). + * <p> + * This annotation is ignored on top-level servlets (i.e. servlets defined in <code>web.xml</code> files). + * Therefore, implementers can optionally specify a path value for documentation purposes. + */ + String path() default ""; + + /** + * Optional servlet label. + * <p> + * The default value pulls the label from the <code>label</code> entry in the servlet resource bundle. + * (e.g. <js>"label = foo"</js> or <js>"MyServlet.label = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + */ + String label() default ""; + + /** + * Optional servlet description. + * <p> + * The default value pulls the description from the <code>description</code> entry in the servlet resource bundle. + * (e.g. <js>"description = foo"</js> or <js>"MyServlet.description = foo"</js>). + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + */ + String description() default ""; + + /** + * Optional location of configuration file for this servlet. + * <p> + * The configuration file . + * <p> + * This field can contain variables (e.g. "$L{my.localized.variable}"). + */ + String config() default ""; + + /** + * The stylesheet to use for HTML views. + * <p> + * The name is a path to a stylesheet located in either the classpath or working directory. + * The resulting stylesheet becomes available through the servlet via the URL <js>"[servletpath]/style.css"</js>. + * <p> + * The default set of styles located in the <code>org.apache.juneau.server.styles</code> package are: + * <ul class='spaced-list'> + * <li><js>"styles/juneau.css"</js> - Theme based on Jazz look-and-feel. + * <li><js>"styles/devops.css"</js> - Theme based on IBM DevOps look-and-feel. + * </ul> + * <p> + * The classpath search starts with the child servlet class and proceeds up the class hierarchy + * chain. Since the {@link RestServlet} class is in the <code>org.apache.juneau.server</code> package + * and the predefined styles are in the <code>org.apache.juneau.server.styles</code> package, the paths to + * the predefined styles are prefixed with <js>"styles/"</js>. + * <p> + * If the stylesheet cannot be found on the classpath, an attempt to look in the working directory + * for it will be made. This allows for stylesheets to be placed on the file system in the working + * directory. + * <p> + * If the file cannot be located, the request to <js>"[servletpath]/style.css"</js> will return {@link HttpServletResponse#SC_NOT_FOUND}. + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jk>package</jk> com.ibm.mypackage; + * + * <ja>@RestResource</ja>( + * stylesheet=<js>"mystyles/mycss.css"</js> + * ) + * <jk>public class</jk> MyResource <jk>extends</jk> RestServletDefault { + * } + * </p> + * <p> + * In this example, the servlet will attempt to find the <code>mycss.css</code> file in the following ordered locations: + * </p> + * <ol> + * <li><code>com.ibm.mypackage.mystyles</code> package. + * <li><code>org.apache.juneau.server.mystyles</code> package (since <code>RestServletDefault</code> is in <code>org.apache.juneau.server</code>). + * <li><code>[working-dir]/mystyles</code> directory. + * </ol> + * </dd> + * </dl> + */ + String stylesheet() default ""; + + /** + * The favicon to use for HTML views. + * <p> + * The name is a path to an icon file located in either the classpath or working directory in a similar way + * to how the {@link #stylesheet()} stylesheet is resolved. + * The resulting favicon becomes available in the servlet via the URL <js>"[servletpath]/favicon.ico"</js>. + * <p> + * If the file cannot be located, the request to <js>"[servletpath]/favicon.ico"</js> will return {@link HttpServletResponse#SC_NOT_FOUND}. + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jk>package</jk> com.ibm.mypackage; + * + * <ja>@RestResource</ja>( + * favicon=<js>"mydocs/myicon.ico"</js> + * ) + * <jk>public class</jk> MyResource <jk>extends</jk> RestServletDefault { + * } + * </p> + * <p> + * In this example, the servlet will attempt to find the <code>myicon.ico</code> file in the following ordered locations: + * </p> + * <ol> + * <li><code>com.ibm.mypackage.mydocs</code> package. + * <li><code>org.apache.juneau.server.mydocs</code> package (since <code>RestServletDefault</code> is in <code>org.apache.juneau.server</code>). + * <li><code>[working-dir]/mydocs</code> directory. + * </ol> + * </dd> + * </dl> + */ + String favicon() default ""; + + /** + * Defines paths and locations of statically served files. + * <p> + * This is a JSON map of paths to packages/directories located on either the classpath or working directory. + * <p> + * Mappings are cumulative from parent to child. Child resources can override mappings made on parent resources. + * <p> + * If the file cannot be located, the request will return {@link HttpServletResponse#SC_NOT_FOUND}. + * <p> + * The media type on the response is determined by the {@link RestServlet#getMimetypesFileTypeMap()} method. + * + * <dl> + * <dt>Example:</dt> + * <dd> + * <p class='bcode'> + * <jk>package</jk> com.ibm.mypackage; + * + * <ja>@RestResource</ja>( + * path=<js>"/myresource"</js>, + * staticFiles=<js>"{htdocs:'docs'}"</js> + * ) + * <jk>public class</jk> MyResource <jk>extends</jk> RestServletDefault { + * } + * </p> + * <p> + * In this example, given a GET request to <code>/myresource/htdocs/foobar.html</code>, the servlet will attempt to find the <code>foobar.html</code> file + * in the following ordered locations: + * </p> + * <ol> + * <li><code>com.ibm.mypackage.docs</code> package. + * <li><code>org.apache.juneau.server.docs</code> package (since <code>RestServletDefault</code> is in <code>org.apache.juneau.server</code>). + * <li><code>[working-dir]/docs</code> directory. + * </ol> + * </dd> + * </dl> + */ + String staticFiles() default ""; + + /** + * Specifies the HTTP header name used to identify the client version. + * <p> + * The client version is used to support backwards compatibility for breaking REST interface + * changes. Used in conjunction with {@link RestMethod#clientVersion()} annotation. + * <p> + * If not specified, uses <js>"X-Client-Version"</js>. + */ + String clientVersionHeader() default ""; + +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Var.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Var.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Var.java new file mode 100755 index 0000000..16c0db5 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/Var.java @@ -0,0 +1,70 @@ +/*************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + ***************************************************************************************************************************/ +package org.apache.juneau.server.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Annotation used in conjunction with {@link RestMethod#input()} and {@link Response#output()} to identify content and header descriptions + * on specific method responses. + * + * <h6 class='topic'>Example</h6> + * <p class='bcode'> + * <ja>@RestMethod</ja>( + * name=<js>"*"</js>, + * requestVars={ + * <ja>@Var</ja>(category=<js>"header"</js>,name=<js>"Range"</js>,description=<js>"$L{ContentRange.description}"</js>) + * } + * responses={ + * <ja>@Response</ja>(code=200,description=<js>"Everything was great."</js>, + * responseVars={ + * <ja>@Var</ja>(category=<js>"header"</js>,name=<js>"Content-Range"</js>,description=<js>"$L{ContentRange.description}"</js>) + * }) + * <ja>@Response</ja>(code=404,description=<js>"File was not found."</js>) + * } + * ) + * <jk>public void</jk> doAnything(RestRequest req, RestResponse res, <ja>@Method</ja> String method) { + * ... + * } + * </p> + * + * @author James Bognar (james.bog...@salesforce.com) + */ +@Documented +@Target(PARAMETER) +@Retention(RUNTIME) +@Inherited +public @interface Var { + + /** + * Variable category (e.g. <js>"header"</js>, <js>"content"</js>). + * The {@link VarCategory} class contains predefined constants. + */ + String category(); + + /** + * Variable name (e.g. <js>"Content-Range"</js>). + */ + String name() default ""; + + /** + * Variable description (e.g. <js>"Indicates the range returned when Range header is present in the request"</js>). + * <p> + * The default value pulls the description from the <code>description</code> entry in the servlet resource bundle. + * (e.g. <js>"myMethod.res.[code].[category].[name] = foo"</js> or <js>"MyServlet.myMethod.res.[code].[category].[name] = foo"</js>). + */ + String description() default ""; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/VarCategory.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/VarCategory.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/VarCategory.java new file mode 100755 index 0000000..3d80d01 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/VarCategory.java @@ -0,0 +1,36 @@ +/*************************************************************************************************************************** + * 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.server.annotation; + +/** + * Predefined string constants for the {@link Var#category()} annotation. + * + * @author James Bognar (james.bog...@salesforce.com) + */ +public class VarCategory { + + /** Constant: 'attr'*/ + public static final String ATTR = "attr"; + + /** Constant: 'param'*/ + public static final String PARAM = "param"; + + /** Constant: 'content'*/ + public static final String CONTENT = "content"; + + /** Constant: 'header'*/ + public static final String HEADER = "header"; + + /** Constant: 'other'*/ + public static final String OTHER = "other"; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/package.html ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/package.html b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/package.html new file mode 100755 index 0000000..c0c0d41 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/annotation/package.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<!-- +/*************************************************************************************************************************** + * 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. + * + ***************************************************************************************************************************/ + --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <style type="text/css"> + /* For viewing in Page Designer */ + @IMPORT url("../../../../javadoc.css"); + + /* For viewing in REST interface */ + @IMPORT url("../htdocs/javadoc.css"); + body { + margin: 20px; + } + </style> + <script> + /* Replace all @code and @link tags. */ + window.onload = function() { + document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); + document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); + } + </script> +</head> +<body> +<p>REST servlet annotations</p> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Introspectable.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Introspectable.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Introspectable.java new file mode 100755 index 0000000..f55fe22 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Introspectable.java @@ -0,0 +1,59 @@ +/*************************************************************************************************************************** + * 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.server.converters; + +import static javax.servlet.http.HttpServletResponse.*; + +import org.apache.juneau.*; +import org.apache.juneau.json.*; +import org.apache.juneau.server.*; +import org.apache.juneau.utils.*; + +/** + * Converter for enablement of {@link PojoIntrospector} support on response objects returned by a <code>@RestMethod</code> method. + * <p> + * When enabled, public methods can be called on objects returned through the {@link RestResponse#setOutput(Object)} method. + * <p> + * Note that opening up public methods for calling through a REST interface can be dangerous, and should + * be done with caution. + * <p> + * Java methods are invoked by passing in the following URL parameters: + * <ul class='spaced-list'> + * <li><code>&invokeMethod</code> - The Java method name, optionally with arguments if necessary to differentiate between methods. + * <li><code>&invokeArgs</code> - The arguments as a JSON array. + * </ul> + * <p> + * See {@link PojoIntrospector} for additional information on introspecting POJO methods. + */ +public final class Introspectable implements RestConverter { + + @Override /* RestConverter */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object convert(RestRequest req, Object o, ClassMeta cm) throws RestException { + String method = req.getParameter("invokeMethod"); + String args = req.getParameter("invokeArgs"); + if (method == null) + return o; + try { + if (cm.getPojoTransform() != null) + o = cm.getPojoTransform().transform(o); + return new PojoIntrospector(o, JsonParser.DEFAULT).invokeMethod(method, args); + } catch (Exception e) { + e.printStackTrace(); + return new RestException(SC_INTERNAL_SERVER_ERROR, + "Error occurred trying to invoke method: {0}", + e.getLocalizedMessage() + ).initCause(e); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Queryable.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Queryable.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Queryable.java new file mode 100755 index 0000000..088aa97 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Queryable.java @@ -0,0 +1,96 @@ +/*************************************************************************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + ***************************************************************************************************************************/ +package org.apache.juneau.server.converters; + +import static javax.servlet.http.HttpServletResponse.*; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.server.*; +import org.apache.juneau.utils.*; + +/** + * Converter for enablement of {@link PojoQuery} support on response objects returned by a <code>@RestMethod</code> method. + * <p> + * When enabled, objects in a POJO tree can be filtered using the functionality described in the {@link PojoQuery} + * class. + * <p> + * The following HTTP request parameters are available for tabular data (e.g. {@code Collections} of {@code Maps}, arrays of beans, etc...): + * <ul class='spaced-list'> + * <li><b>&q=<i>JSON-object</i></b> - Query parameter. Only return rows that match the specified search string. <br> + * The JSON object keys are column names, and the values are search parameter strings.<br> + * Example: <code>&s=(name=Bill*,birthDate=>2000)</code> + * <li><b>&v=<i>JSON-array or comma-delimited list</i></b> - View parameter. Only return the specified columns.<br> + * Example: <code>&v=(name,birthDate)</code> + * <li><b>&s=<i>JSON-object</i></b> - Sort parameter. Sort the results by the specified columns.<br> + * The JSON object keys are the column names, and the values are either {@code 'A'} for ascending or {@code 'D'} for descending. + * Example: <code>&s=(name=A,birthDate=D)</code> + * <li><b>&i=<i>true/false</i></b> - Case-insensitive parameter. Specify <jk>true</jk> for case-insensitive matching on the {@code &q} parameter. + * <li><b>&p=<i>number</i></b> - Position parameter. Only return rows starting at the specified index position (zero-indexed). Default is {@code 0}. + * <li><b>&q=<i>number</i></b> - Limit parameter. Only return the specified number of rows. Default is {@code 0} (meaning return all rows). + * </ul> + * + * <p> + * The <b>&v</b> parameter can also be used on {@code Maps} and beans. + * + * <p> + * See {@link PojoQuery} for additional information on filtering POJO models. + */ +public final class Queryable implements RestConverter { + + @Override /* RestConverter */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Object convert(RestRequest req, Object o, ClassMeta cm) { + if (o == null) + return null; + + try { + + // If no actual filtering parameters have been passed in, and there is no map augmenter specified, + // then just pass the original object back. + if (req.hasAnyQueryParameters("q","v","s","g","i","p","l")) { + BeanContext bc = req.getBeanContext(); + + if (cm.getPojoTransform() != null) + o = cm.getPojoTransform().transform(o); + + PojoQuery f = new PojoQuery(o, bc); + + if (o instanceof Collection || o.getClass().isArray()) { + ObjectMap query = req.getQueryParameter("q", ObjectMap.class); + ClassMeta<List<String>> cm1 = bc.getCollectionClassMeta(List.class, String.class); + List<String> view = req.getQueryParameter("v", cm1); + ClassMeta<List<Object>> cm2 = bc.getCollectionClassMeta(List.class, String.class); + List sort = req.getQueryParameter("s", cm2); + boolean ignoreCase = req.getQueryParameter("i", Boolean.class, false); + int pos = req.getQueryParameter("p", Integer.class, 0); + int limit = req.getQueryParameter("l", Integer.class, 0); + o = f.filterCollection(query, view, sort, pos, limit, ignoreCase); + + } else { + ClassMeta<List<String>> cm2 = bc.getCollectionClassMeta(List.class, String.class); + List<String> view = req.getQueryParameter("v", cm2); + o = f.filterMap(view); + } + } + return o; + } catch (SerializeException e) { + throw new RestException(SC_BAD_REQUEST, e); + } catch (ParseException e) { + throw new RestException(SC_BAD_REQUEST, e); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Traversable.java ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Traversable.java b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Traversable.java new file mode 100755 index 0000000..ebcdbe9 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/Traversable.java @@ -0,0 +1,67 @@ +/*************************************************************************************************************************** + * 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.server.converters; + +import javax.servlet.http.*; + +import org.apache.juneau.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.server.*; +import org.apache.juneau.utils.*; + +/** + * Converter for enablement of {@link PojoRest} support on response objects returned by a <code>@RestMethod</code> method. + * <p> + * When enabled, objects in a POJO tree returned by the REST method can be addressed through additional URL path information. + * + * <p class='bcode'> + * <jc>// Resource method on resource "http://localhost:8080/sample/addressBook"</jc> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, converters=Traversable.<jk>class</jk>) + * <jk>public void</jk> doGet(RestRequest req, RestResponse res) { + * <jk>return new</jk> AddressBook(); + * } + * + * <jc>// Sample usage</jc> + * <jk>public static void</jk> main(String[] args) { + * <jc>// Get the zip code of the 2nd address of the first person in the address book.</jc> + * RestCall r = <jk>new</jk> RestClient().doGet(<js>"http://localhost:8080/sample/addressBook/0/addresses/1/zip"</js>); + * <jk>int</jk> zip = r.getResponse(Integer.<jk>class</jk>); + * } + * </p> + * <p> + * See {@link PojoRest} for additional information on addressing elements in a POJO tree using URL notation. + */ +public final class Traversable implements RestConverter { + + @Override /* RestConverter */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public Object convert(RestRequest req, Object o, ClassMeta cm) throws RestException { + if (o == null) + return null; + + if (req.getPathRemainder() != null) { + try { + if (cm.getPojoTransform() != null) + o = cm.getPojoTransform().transform(o); + PojoRest p = new PojoRest(o, req.getReaderParser()); + o = p.get(req.getPathRemainder()); + } catch (SerializeException e) { + throw new RestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); + } catch (PojoRestException e) { + throw new RestException(e.getStatus(), e); + } + } + + return o; + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/package.html ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/package.html b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/package.html new file mode 100755 index 0000000..2599329 --- /dev/null +++ b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/converters/package.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<!-- +/*************************************************************************************************************************** + * 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. + * + ***************************************************************************************************************************/ + --> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <style type="text/css"> + /* For viewing in Page Designer */ + @IMPORT url("../../../../javadoc.css"); + + /* For viewing in REST interface */ + @IMPORT url("../htdocs/javadoc.css"); + body { + margin: 20px; + } + </style> + <script> + /* Replace all @code and @link tags. */ + window.onload = function() { + document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>'); + document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>'); + } + </script> +</head> +<body> +<p>Predefined REST response converters</p> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook.png new file mode 100755 index 0000000..96426b7 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookJson.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookJson.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookJson.png new file mode 100755 index 0000000..68c0ec8 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookJson.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookOptions.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookOptions.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookOptions.png new file mode 100755 index 0000000..36c3e42 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBookOptions.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook_juneaustyle.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook_juneaustyle.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook_juneaustyle.png new file mode 100755 index 0000000..94327eb Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/AddressBook_juneaustyle.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource1.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource1.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource1.png new file mode 100755 index 0000000..3b54341 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource1.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource2.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource2.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource2.png new file mode 100755 index 0000000..7a4c816 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource2.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource3.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource3.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource3.png new file mode 100755 index 0000000..dd088bd Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource3.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource4.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource4.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource4.png new file mode 100755 index 0000000..17bdbf6 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResource4.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptions.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptions.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptions.png new file mode 100755 index 0000000..237dc2b Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptions.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptionsJson.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptionsJson.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptionsJson.png new file mode 100755 index 0000000..c528651 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/HelloWorldResourceOptionsJson.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Options2.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Options2.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Options2.png new file mode 100755 index 0000000..52b9ad1 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Options2.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/OptionsPage.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/OptionsPage.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/OptionsPage.png new file mode 100755 index 0000000..c524ede Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/OptionsPage.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Samples_RootResources.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Samples_RootResources.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Samples_RootResources.png new file mode 100755 index 0000000..62408e2 Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/Samples_RootResources.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/UrlEncodedForm.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/UrlEncodedForm.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/UrlEncodedForm.png new file mode 100755 index 0000000..2cd173f Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/doc-files/UrlEncodedForm.png differ http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/244cc21a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/htdocs/MethodExampleResource1.png ---------------------------------------------------------------------- diff --git a/org.apache.juneau.server/src/main/java/org/apache/juneau/server/htdocs/MethodExampleResource1.png b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/htdocs/MethodExampleResource1.png new file mode 100755 index 0000000..1ca74fe Binary files /dev/null and b/org.apache.juneau.server/src/main/java/org/apache/juneau/server/htdocs/MethodExampleResource1.png differ