diff --git a/README.md b/README.md index 208f561f6b..eabb7472a7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Restlet Framework -## The leading RESTful Web API framework for Java +## The first REST API framework for Java Thanks to Restlet Framework's powerful routing and filtering capabilities, unified client and server Java API, developers can build secure and scalable RESTful web APIs. @@ -8,22 +8,21 @@ It is available in editions for all major platforms (Java SE/EE, Google App Engi It is available under the terms of either the Apache Software License 2.0 or the Eclipse Public License 1.0. -http://restlet.com +http://restlet.talend.com ## Learn more To learn more about Restlet Framework, please have a look at the following resources: -* [User Guide](http://restlet.com/technical-resources/restlet-framework/guide/2.3) -* [Tutorials](http://restlet.com/technical-resources/restlet-framework/tutorials/2.3) -* [JavaDocs](http://restlet.com/technical-resources/restlet-framework/javadocs/3.0) -* [Change Log](http://restlet.com/technical-resources/restlet-framework/misc/3.0/changes) -* [Download](http://restlet.com/downloads/current/) +* [User Guide](https://restlet.talend.com/documentation/user-guide/2.4/) +* [Tutorials](https://restlet.talend.com/documentation/tutorials/2.4/) +* [JavaDocs](https://restlet.talend.com/documentation/javadocs/2.4/) +* [Change Log](https://restlet.talend.com/documentation/2.4/changelog) +* [Download](https://restlet.talend.com/downloads/current/) * [Issue Tracker](https://github.com/restlet/restlet-framework-java/issues) * [Mailing List](https://groups.google.com/a/restlet.org/forum/#!forum/framework-discuss) * [Stack Overflow](http://stackoverflow.com/questions/tagged/restlet) -Copyright 2015 Restlet - -[![Build Status](https://travis-ci.org/restlet/restlet-framework-java.png?branch=master)](https://travis-ci.org/restlet/restlet-framework-java) +Copyright 2024 Qlik +[![Build Status](https://travis-ci.org/restlet/restlet-framework-java.svg?branch=master)](https://travis-ci.org/restlet/restlet-framework-java) diff --git a/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/CallContext.java b/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/CallContext.java index 98212e61a2..edc99f373b 100644 --- a/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/CallContext.java +++ b/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/CallContext.java @@ -989,7 +989,7 @@ public MultivaluedMap getQueryParameters() { if (this.queryParametersDecoded == null) { this.queryParametersDecoded = UnmodifiableMultivaluedMap .getFromSeries(this.referenceOriginal.getQueryAsForm(), - false); + true); } return this.queryParametersDecoded; } @@ -1000,12 +1000,15 @@ public MultivaluedMap getQueryParameters() { * @param decode * controls whether sequences of escaped octets in parameter * names and values are decoded (true) or not (false). + * @param caseSensitive + * should the parameter name should keep their case, set to true * @return an unmodifiable map of query parameter names and values * @throws java.lang.IllegalStateException * if called outside the scope of a request * @see UriInfo#getQueryParameters(boolean) */ - public MultivaluedMap getQueryParameters(boolean decode) { + public MultivaluedMap getQueryParameters(boolean decode, + boolean caseSensitive) { if (decode) { return getQueryParameters(); } @@ -1014,7 +1017,7 @@ public MultivaluedMap getQueryParameters(boolean decode) { Form queryForm = Converter.toFormEncoded(this.referenceOriginal .getQuery()); this.queryParametersEncoded = UnmodifiableMultivaluedMap - .getFromSeries(queryForm, false); + .getFromSeries(queryForm, caseSensitive); } return this.queryParametersEncoded; diff --git a/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/ThreadLocalizedUriInfo.java b/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/ThreadLocalizedUriInfo.java index aecd61cd4f..74375154a6 100644 --- a/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/ThreadLocalizedUriInfo.java +++ b/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/core/ThreadLocalizedUriInfo.java @@ -200,7 +200,16 @@ public MultivaluedMap getQueryParameters() { * @see UriInfo#getQueryParameters(boolean) */ public MultivaluedMap getQueryParameters(boolean decode) { - return getCallContext().getQueryParameters(decode); + return getCallContext().getQueryParameters(decode, true); + } + + /** + * @see JaxRsUriInfo#getQueryParameters(boolean) + * @see UriInfo#getQueryParameters(boolean) + */ + public MultivaluedMap getQueryParameters(boolean decode, + boolean caseSensitive) { + return getCallContext().getQueryParameters(decode, caseSensitive); } /** diff --git a/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/wrappers/params/ParameterList.java b/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/wrappers/params/ParameterList.java index 73a97e8ae3..231762b4a2 100644 --- a/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/wrappers/params/ParameterList.java +++ b/modules/org.restlet.ext.jaxrs/src/org/restlet/ext/jaxrs/internal/wrappers/params/ParameterList.java @@ -424,8 +424,7 @@ private void handleExceptionOnInvocation(String value, Exception e) } else if (!(e instanceof NoSuchMethodException) && !(e instanceof IllegalAccessException) && !(e instanceof InvocationTargetException) - && !(e instanceof InstantiationException) - && !(e instanceof NoSuchMethodException)) { + && !(e instanceof InstantiationException)) { throw ConvertParameterException .object(this.convertTo, value, e); } diff --git a/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/OAuthParameters.java b/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/OAuthParameters.java index e6adec6a68..c4a6927fa5 100644 --- a/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/OAuthParameters.java +++ b/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/OAuthParameters.java @@ -29,6 +29,7 @@ import java.util.logging.Logger; import org.restlet.data.Form; +import org.restlet.data.Parameter; import org.restlet.data.Reference; import org.restlet.ext.oauth.internal.Scopes; import org.restlet.representation.Representation; @@ -118,6 +119,17 @@ public Reference toReference(String uri) { reference.setQuery(query); return reference; } + + public Reference toReference(Reference ref) { + Reference reference = new Reference(ref); + + //Add each parameter to avoid overwriting existing parameters + for(Parameter param : form){ + reference.addQueryParameter(param); + } + + return reference; + } public Representation toRepresentation() { return form.getWebRepresentation(); diff --git a/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/ProtectedClientResource.java b/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/ProtectedClientResource.java index a7fcda719e..a4e7d60c0e 100644 --- a/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/ProtectedClientResource.java +++ b/modules/org.restlet.ext.oauth/src/org/restlet/ext/oauth/ProtectedClientResource.java @@ -128,7 +128,7 @@ public Response handleOutbound(Request request) { throw new ResourceException(Status.CLIENT_ERROR_UNAUTHORIZED, "Token not found"); } - if (token.getTokenType().equals(TOKEN_TYPE_BEARER)) { + if (TOKEN_TYPE_BEARER.equalsIgnoreCase(token.getTokenType())) { if (isUseBodyMethod()) { Representation entity = request.getEntity(); if (entity != null diff --git a/modules/org.restlet.ext.servlet/src/org/restlet/ext/servlet/internal/ServletServerAdapter.java b/modules/org.restlet.ext.servlet/src/org/restlet/ext/servlet/internal/ServletServerAdapter.java index b9ee64f2ba..1024d043c5 100644 --- a/modules/org.restlet.ext.servlet/src/org/restlet/ext/servlet/internal/ServletServerAdapter.java +++ b/modules/org.restlet.ext.servlet/src/org/restlet/ext/servlet/internal/ServletServerAdapter.java @@ -85,8 +85,10 @@ public HttpRequest toRequest(ServerCall httpCall) { for (final Enumeration namesEnum = servletCall.getRequest() .getAttributeNames(); namesEnum.hasMoreElements();) { attributeName = namesEnum.nextElement(); - result.getAttributes().put(attributeName, - servletCall.getRequest().getAttribute(attributeName)); + Object attribute = servletCall.getRequest().getAttribute(attributeName); + if (attribute != null) { + result.getAttributes().put(attributeName, attribute); + } } } diff --git a/modules/org.restlet.test/src/org/restlet/test/data/MethodTestCase.java b/modules/org.restlet.test/src/org/restlet/test/data/MethodTestCase.java new file mode 100644 index 0000000000..c36fcd9d5c --- /dev/null +++ b/modules/org.restlet.test/src/org/restlet/test/data/MethodTestCase.java @@ -0,0 +1,53 @@ +/** + * 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.test.data; + +import org.restlet.data.Method; + +import junit.framework.TestCase; + +/** + * Test {@link org.restlet.data.Method}. + *

+ * Note: this test purposefully does *not* extends RestletTestCase. The + * regression previously present in Restlet + * (desribed in https://github.com/restlet/restlet-framework-java/issues/1130) depends on + * class initialization order and vanishes when the Restlet/Engine class is + * initialized before the class Method. + * + * @author Andreas Wundsam + */ +public class MethodTestCase extends TestCase { + + /** + * validate that Method caching works, i.e., the value returned by + * Method.valueOf("GET") is the cached constant Method.GET + */ + public void testCaching() { + assertTrue("Method.valueOf('GET') should return cached constant Method.GET ", + Method.GET == Method.valueOf("GET")); + } + +} diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthParametersTest.java b/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthParametersTest.java index 2acb55c3f0..dedc815adc 100644 --- a/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthParametersTest.java +++ b/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthParametersTest.java @@ -64,4 +64,16 @@ public void testToReference() { assertEquals("val2", form.getFirstValue("bar")); assertEquals("val3", form.getFirstValue("buz")); } + + @Test + public void testToReferenceFromReference() { + Reference originalReference = new Reference("http://localhost/test?existing=thing"); + + Reference reference = parameters.toReference(originalReference); + Form form = reference.getQueryAsForm(); + assertEquals("thing", form.getFirstValue("existing")); + assertEquals("val1", form.getFirstValue("foo")); + assertEquals("val2", form.getFirstValue("bar")); + assertEquals("val3", form.getFirstValue("buz")); + } } diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthTestBase.java b/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthTestBase.java index 6395a9f8b9..b3bcfde802 100644 --- a/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthTestBase.java +++ b/modules/org.restlet.test/src/org/restlet/test/ext/oauth/OAuthTestBase.java @@ -91,6 +91,42 @@ public boolean isExpired() { return false; } }; + + public static Token SPRING_STUB_TOKEN = new ServerToken() { + + public String getAccessToken() { + return STUB_ACCESS_TOKEN; + } + + public String getTokenType() { + //Spring returns bearer in lower case + return "bearer"; + } + + public int getExpirePeriod() { + return 3600; + } + + public String getRefreshToken() { + return STUB_REFRESH_TOKEN; + } + + public String[] getScope() { + return new String[] { "a", "b" }; + } + + public String getUsername() { + return STUB_USERNAME; + } + + public String getClientId() { + return STUB_CLIENT_ID; + } + + public boolean isExpired() { + return false; + } + }; public static final Client STUB_CLIENT = new Client() { diff --git a/modules/org.restlet.test/src/org/restlet/test/ext/oauth/ProtectedClientResourceTest.java b/modules/org.restlet.test/src/org/restlet/test/ext/oauth/ProtectedClientResourceTest.java index a3e19c872e..7b20c595c2 100644 --- a/modules/org.restlet.test/src/org/restlet/test/ext/oauth/ProtectedClientResourceTest.java +++ b/modules/org.restlet.test/src/org/restlet/test/ext/oauth/ProtectedClientResourceTest.java @@ -152,4 +152,14 @@ public void testCase3() { resource.addQueryParameter("foo", "bar"); resource.get(); } + + //Test compatibility with modules that don't match token type case + @Test + public void testCase4() { + ProtectedClientResource resource = new ProtectedClientResource( + new Reference(baseURI, "/app/resource1")); + resource.setToken(SPRING_STUB_TOKEN); + resource.setUseBodyMethod(false); + resource.get(); + } } diff --git a/modules/org.restlet/src/org/restlet/data/Method.java b/modules/org.restlet/src/org/restlet/data/Method.java index 19f185ebb5..583a486f81 100644 --- a/modules/org.restlet/src/org/restlet/data/Method.java +++ b/modules/org.restlet/src/org/restlet/data/Method.java @@ -237,7 +237,7 @@ public static Method valueOf(final String name) { /** 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. diff --git a/modules/org.restlet/src/org/restlet/engine/connector/HttpServerHelper.java b/modules/org.restlet/src/org/restlet/engine/connector/HttpServerHelper.java index 4c489a5ac7..74c730a623 100644 --- a/modules/org.restlet/src/org/restlet/engine/connector/HttpServerHelper.java +++ b/modules/org.restlet/src/org/restlet/engine/connector/HttpServerHelper.java @@ -24,15 +24,15 @@ package org.restlet.engine.connector; -import java.io.IOException; -import java.net.InetSocketAddress; - -import org.restlet.Server; -import org.restlet.data.Protocol; - import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import org.restlet.Server; +import org.restlet.data.Protocol; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; /** * Internal HTTP server connector. @@ -56,8 +56,22 @@ public HttpServerHelper(Server server) { @Override public void start() throws Exception { - this.server = HttpServer.create(new InetSocketAddress(getHelped() - .getPort()), 0); + String addr = getHelped().getAddress(); + // Use ephemeral port + int port = getHelped().getPort() > 0 ? getHelped().getPort() : 0; + + if (addr != null) { + // This call may throw UnknownHostException and otherwise always + // returns an instance of INetAddress. + // Note: textual representation of inet addresses are supported + InetAddress iaddr = InetAddress.getByName(addr); + setAddress(new InetSocketAddress(iaddr, port)); + } else { + setAddress(new InetSocketAddress(port)); + } + + // Complete initialization + server = HttpServer.create(getAddress(), 0); server.createContext("/", new HttpHandler() { @Override public void handle(HttpExchange httpExchange) throws IOException { diff --git a/modules/org.restlet/src/org/restlet/engine/connector/HttpsServerHelper.java b/modules/org.restlet/src/org/restlet/engine/connector/HttpsServerHelper.java index 54f95e6cf6..e81577152e 100644 --- a/modules/org.restlet/src/org/restlet/engine/connector/HttpsServerHelper.java +++ b/modules/org.restlet/src/org/restlet/engine/connector/HttpsServerHelper.java @@ -24,24 +24,22 @@ package org.restlet.engine.connector; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; - +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; import org.restlet.Server; import org.restlet.data.Protocol; import org.restlet.engine.ssl.DefaultSslContextFactory; import org.restlet.engine.ssl.SslContextFactory; import org.restlet.engine.ssl.SslUtils; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpsConfigurator; -import com.sun.net.httpserver.HttpsParameters; -import com.sun.net.httpserver.HttpsServer; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; /** * Internal HTTPS server connector. Here is the list of additional parameters @@ -90,28 +88,24 @@ public void start() throws Exception { SslContextFactory sslContextFactory = SslUtils .getSslContextFactory(this); SSLContext sslContext = sslContextFactory.createSslContext(); + String addr = getHelped().getAddress(); + // Use ephemeral port + int port = getHelped().getPort() > 0 ? getHelped().getPort() : 0; if (addr != null) { // This call may throw UnknownHostException and otherwise always // returns an instance of INetAddress. // Note: textual representation of inet addresses are supported InetAddress iaddr = InetAddress.getByName(addr); - - // Note: the backlog of 50 is the default - setAddress(new InetSocketAddress(iaddr, getHelped().getPort())); + setAddress(new InetSocketAddress(iaddr, port)); } else { - int port = getHelped().getPort(); - - // Use ephemeral port - if (port > 0) { - setAddress(new InetSocketAddress(getHelped().getPort())); - } + setAddress(new InetSocketAddress(port)); } // Complete initialization - this.server = HttpsServer.create(new InetSocketAddress(getHelped() - .getPort()), 0); + server = HttpsServer.create(getAddress(), 0); + final SSLParameters sslParams = sslContext.getDefaultSSLParameters(); server.setHttpsConfigurator(new HttpsConfigurator(sslContext) { public void configure(HttpsParameters params) { diff --git a/modules/org.restlet/src/org/restlet/engine/io/PipeStream.java b/modules/org.restlet/src/org/restlet/engine/io/PipeStream.java index 97757f049e..903e67d9c5 100644 --- a/modules/org.restlet/src/org/restlet/engine/io/PipeStream.java +++ b/modules/org.restlet/src/org/restlet/engine/io/PipeStream.java @@ -69,12 +69,12 @@ public int read() throws IOException { final Integer value = queue.poll(QUEUE_TIMEOUT, TimeUnit.SECONDS); - this.endReached = (value == -1); if (value == null) { throw new IOException( "Timeout while reading from the queue-based input stream"); } else { + this.endReached = (value == -1); return value.intValue(); } } catch (InterruptedException ie) {