/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.data;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.restlet.engine.Engine;
/**
* Method to execute when handling a call.
*
* @author Jerome Louvel
*/
public final class Method implements Comparable<Method> {
/** Map of registered methods. */
private static final Map<String, Method> _methods = new ConcurrentHashMap<String, Method>();
/**
* Pseudo-method use to match all methods.
*/
public static final Method ALL = new Method("*",
"Pseudo-method use to match all methods.");
private static final String BASE_HTTP = "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html";
/**
* Used with a proxy that can dynamically switch to being a tunnel.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.9">HTTP
* RFC - 9.9 CONNECT</a>
*/
public static final Method CONNECT = new Method("CONNECT",
"Used with a proxy that can dynamically switch to being a tunnel",
BASE_HTTP + "#sec9.9", false, false);
/**
* Requests that the origin server deletes the resource identified by the
* request URI.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7">HTTP
* RFC - 9.7 DELETE</a>
*/
public static final Method DELETE = new Method(
"DELETE",
"Requests that the origin server deletes the resource identified by the request URI",
BASE_HTTP + "#sec9.7", false, true);
/**
* Retrieves whatever information (in the form of an entity) that is
* identified by the request URI.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3">HTTP
* RFC - 9.3 GET</a>
*/
public static final Method GET = new Method(
"GET",
"Retrieves whatever information (in the form of an entity) that is identified by the request URI",
BASE_HTTP + "#sec9.3", true, true);
/**
* Identical to GET except that the server must not return a message body in
* the response but only the message header.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4">HTTP
* RFC - 9.4 HEAD</a>
*/
public static final Method HEAD = new Method(
"HEAD",
"Identical to GET except that the server must not return a message body in the response",
BASE_HTTP + "#sec9.4", true, true);
/**
* Requests for information about the communication options available on the
* request/response chain identified by the URI.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2">HTTP
* RFC - 9.2 OPTIONS</a>
*/
public static final Method OPTIONS = new Method(
"OPTIONS",
"Requests for information about the communication options available on the request/response chain identified by the URI",
BASE_HTTP + "#sec9.2", true, true);
/**
* Requests that the origin server applies partial modifications contained
* in the entity enclosed in the request to the resource identified by the
* request URI.
*
* @see <a href="http://tools.ietf.org/html/rfc5789">HTTP PATCH RFC 5789</a>
*/
public static final Method PATCH = new Method(
"PATCH",
"Requests that the origin server applies partial modifications to the resource identified by the request URI",
"http://tools.ietf.org/html/rfc5789", false, false);
/**
* Requests that the origin server accepts the entity enclosed in the
* request as a new subordinate of the resource identified by the request
* URI.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5">HTTP
* RFC - 9.5 POST</a>
*/
public static final Method POST = new Method(
"POST",
"Requests that the origin server accepts the entity enclosed in the request as a new subordinate of the resource identified by the request URI",
BASE_HTTP + "#sec9.5", false, false);
/**
* Requests that the enclosed entity be stored under the supplied request
* URI.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6"
* HTTP RFC - 9.6 PUT</a>
*/
public static final Method PUT = new Method(
"PUT",
"Requests that the enclosed entity be stored under the supplied request URI",
BASE_HTTP + "#sec9.6", false, true);
/**
* Used to invoke a remote, application-layer loop-back of the request
* message.
*
* @see <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.8">HTTP
* RFC - 9.8 TRACE</a>
*/
public static final Method TRACE = new Method(
"TRACE",
"Used to invoke a remote, application-layer loop-back of the request message",
BASE_HTTP + "#sec9.8", true, true);
/**
* Adds a new Method to the list of registered methods.
*
* @param method
* The method to register.
*/
public static void register(Method method) {
String name = (method == null) ? null : method.getName().toLowerCase();
if ((name != null) && !name.equals("")) {
_methods.put(name, method);
}
}
/**
* Sorts the given list of methods by name.
*
* @param methods
* The methods to sort.
*/
public static void sort(List<Method> methods) {
Collections.sort(methods, new Comparator<Method>() {
public int compare(Method m1, Method m2) {
return m1.getName().compareTo(m2.getName());
}
});
}
/**
* Returns the method associated to a given method name. If an existing
* constant exists then it is returned, otherwise a new instance is created.
*
* @param name
* The method name.
* @return The associated method.
*/
public static Method valueOf(final String name) {
Method result = null;
if ((name != null) && !name.equals("")) {
result = Method._methods.get(name.toLowerCase());
if (result == null) {
result = new Method(name);
}
}
return result;
}
/** The description. */
private final String description;
/**
* Indicates if the side-effects of several requests is the same as a single
* request.
*/
private volatile boolean idempotent;
/** The name. */
private volatile String name;
/** Indicates if the method replies with a response. */
private final boolean replying;
/**
* Indicates if it should have the significance of taking an action other
* than retrieval.
*/
private final boolean safe;
/** The URI of the specification describing the method. */
private volatile String uri;
static {
// Let the engine register all methods (the default ones and the ones to
// be discovered) as soon as the Method class is loaded or at least
// used.
Engine.getInstance();
}
/**
* Constructor for unsafe and non idempotent methods.
*
* @param name
* The technical name of the method.
* @see org.restlet.data.Method#valueOf(String)
*/
public Method(final String name) {
this(name, null);
}
/**
* Constructor for unsafe and non idempotent methods.
*
* @param name
* The technical name of the method.
* @param description
* The description.
* @see org.restlet.data.Method#valueOf(String)
*/
public Method(String name, String description) {
this(name, description, null, false, false);
}
/**
* Constructor for unsafe and non idempotent methods.
*
* @param name
* The technical name.
* @param description
* The description.
* @param uri
* The URI of the specification describing the method.
* @see org.restlet.data.Method#valueOf(String)
*/
public Method(String name, String description, String uri) {
this(name, description, uri, false, false);
}
/**
* Constructor for methods that reply to requests with responses.
*
* @param name
* The technical name.
* @param description
* The description.
* @param uri
* The URI of the specification describing the method.
* @param safe
* Indicates if the method is safe.
* @param idempotent
* Indicates if the method is idempotent.
* @see org.restlet.data.Method#valueOf(String)
*/
public Method(String name, String description, String uri, boolean safe,
boolean idempotent) {
this(name, description, uri, safe, idempotent, true);
}
/**
* Constructor.
*
* @param name
* The technical name.
* @param description
* The description.
* @param uri
* The URI of the specification describing the method.
* @param safe
* Indicates if the method is safe.
* @param idempotent
* Indicates if the method is idempotent.
* @param replying
* Indicates if the method replies with a response.
* @see org.restlet.data.Method#valueOf(String)
*/
public Method(String name, String description, String uri, boolean safe,
boolean idempotent, boolean replying) {
this.name = name;
this.description = description;
this.uri = uri;
this.safe = safe;
this.idempotent = idempotent;
this.replying = replying;
}
/**
* Compares this method to another. Based on the method name.
*
* @param o
* The other method.
*/
public int compareTo(Method o) {
if (o != null) {
return this.getName().compareTo(o.getName());
}
return 1;
}
/** {@inheritDoc} */
@Override
public boolean equals(final Object object) {
return (object instanceof Method)
&& ((Method) object).getName().equals(getName());
}
/**
* Returns the description.
*
* @return The description.
*/
public String getDescription() {
return this.description;
}
/**
* Returns the name.
*
* @return The name.
*/
public String getName() {
return name;
}
/**
* Returns the URI of the specification describing the method.
*
* @return The URI of the specification describing the method.
*/
public String getUri() {
return this.uri;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return (getName() == null) ? 0 : getName().hashCode();
}
/**
* Indicates if the side-effects of several requests is the same as a single
* request.
*
* @return True if the method is idempotent.
*/
public boolean isIdempotent() {
return idempotent;
}
/**
* Indicates if the method replies with a response.
*
* @return True if the method replies with a response.
*/
public boolean isReplying() {
return replying;
}
/**
* Indicates if it should have the significance of taking an action other
* than retrieval.
*
* @return True if the method is safe.
*/
public boolean isSafe() {
return safe;
}
/**
* Returns the name.
*
* @return The name.
*/
@Override
public String toString() {
return getName();
}
}