Last week we released Jersey 1.13 after the long 4+ months! Since the team is now fully focusing on KrakenJersey 2.0 and JAX-RS 2.0 development, this is mostly a bug-fixing release. Anyway, we did manage to address a number of interesting issues. As for any other Jersey 1.x release, the list of changes can be found in changes.txt file in the root of our repository.
The main changes were around JSON handling – Michal, one of our new team-mates, got rid of our custom JSON stream reader and replaced it with a Jackson-based one to make our JSON-JAXB binding more robust. He also made some fixes and improvements to Jersey integration with MOXy JAXB implementation. We received a few external code contributions – from Edouard Chevalier (fixing the interaction of GZIP encoding filter with ETags) and from Atlassian – thank you guys! Finally, I ported the proxy client to Jersey 1.x. It is available in the Jersey 1.x svn repository under experimental/proxy-client (you won’t find it mentioned in changes.txt given it is an experimental module).
Now, that early builds of Jersey 2.0 are integrated into GlassFish application server main trunk (which Jakub is still planning to blog about) more people have to deal with the reality that Jersey 2.0 is not compatible with Jersey 1.x. All the internal Jersey API’s underwent a significant refactoring in Jersey 2.0. And people started asking if there is any way of designing the web application (WAR-based) so that it can run on GlassFish 3.x (which bundles Jersey 1.x) while also being able to run with GlassFish main trunk (that now bundles Jersey 2.0 milestone builds). So, I decided to spend my last week’s “weekend coding” on creating a simple jar that one can bundle in their war to enable this. As a result, I added a new maven module under jersey/ext (in Jersey 2.0 workspace) called servlet-portability. You can build it and add it to your application as a dependency. Now, here is what it does and what it doesn’t do:
It provides PortableServletContainer class you can use in web.xml instead of the Jersey version-specific ServletContainer class to register a Jersey servlet.
It enables your application to bundle Jersey 2.x-specific code along with Jersey 1.x-specific code and helps to ensure the right code gets loaded depending on which version of the Jersey runtime is on the runtime classpath.
It does not provide a compatibility layer – in other words, it does not enable you to use API’s from Jersey 1.x with Jersey 2.x runtime – i.e. in your web app you have to write the Jersey version-specific code twice – one class using Jersey 1.x API’s and another one using Jersey 2.x API’s.
Example Application
Here is how you can use it. I will build a simple application with the following requirements:
Use package-scanning for discovering all the resources and providers that are using pure JAX-RS API (i.e. are not using any version-specific Jersey API’s)
Expose one resource that will require different implementation depending on Jersey version
Getting Jersey 2.0 Source Code and Building It
To try this out let’s first get Jersey 2.0 source code. You can do it in one of the following ways:
Clone Jersey git repository on java.net by executing the following in the terminal:
git clone ssh://<your_java_net_userid>@git.java.net/jersey~code jersey
, or
Clone Jersey git repository on github.com by executing the following in the terminal:
git clone git://github.com/jersey/jersey.git
Now, to build the code execute the following in the source tree root:
mvn clean install -Dmaven.test.skip=true
Creating a New Web Application Project
We will use Jersey 2.0 web application maven archetype to quickly create a skeleton of a new Jersey web application. To do that, switch to the directory where you want your project to reside and execute the following command in that directory:
You should see a new simple-service subdirectory got created that contains the project files. Now, open this project in your favorite IDE. You should see it is a simple project containing a single resource called MyResource (in com.example package) and registering Jersey servlet using web.xml descriptor.
Updating the pom.xml
Let’s update the pom.xml of the project to add a dependency on the portability module, change the scope of Jersey 2.0 servlet dependency to “provided” (so that the Jersey jars are not bundled in our war) and add Jersey 1.x servlet dependency. The resulting pom.xml should look as follows:
Create two new sub-packages – com.example.jersey1 and com.example.jersey2. We will use these for version-specific classes. Let’s create a new resource in com.example.jersey2 package and name it InfoResource. Just for illustration, it will inject ResourceConfig class from Jersey 2 API, retrieve the value of “example.text” property and return it back to the client. Here is how the resource class looks like:
package com.example.jersey2;
import javax.ws.rs.GET;
import javax.ws.rs.core.Context;
import org.glassfish.jersey.server.ResourceConfig;
public class InfoResource {
private @Context ResourceConfig rc;
@GET
public String get() {
return (String) rc.getProperty("example.text");
}
}
As you can see on line 5 it uses Jersey version-specific class. Let’s clone this into com.example.jersey1 package, changing just the import statement to import ResourceConfig from Jersey 1.x package. Here is how the InfoResource in com.example.jersey1 should look like:
package com.example.jersey1;
import javax.ws.rs.GET;
import javax.ws.rs.core.Context;
import com.sun.jersey.api.core.ResourceConfig;
public class InfoResource {
private @Context ResourceConfig rc;
@GET
public String get() {
return (String) rc.getProperty("example.text");
}
}
One important thing to note here is I haven’t annotated InfoResource using the @Path annotation. This is to make sure it does not get picked up by the package scanning (otherwise it would result in Jersey 2-specific resource being loaded when only Jersey 1.x runtime is present or vice-versa). We will use the “explicit root resources” feature from Jersey 1.x and resource builder API from Jersey 2.0 to register this unannotated resource into the Jersey runtime. We need to implement a custom ResourceConfig class for that.
Implementing ResourceConfig
Add ExampleResourceConfig class to com.example.jersey2 package and configure it to scan “com.example” package for resources and providers and map InfoResource to “info” path using the resource builder API. Here is the source code:
package com.example.jersey2;
import java.util.ArrayList;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceModelIssue;
public class ExampleResourceConfig extends ResourceConfig {
public ExampleResourceConfig() {
// look for resources in com.example package and its subpackages
this.packages("com.example");
// create a resource builder from the InfoResource class
// (sending in dummy issues list - we don't expect introspection issues)
Resource.Builder rb = Resource.builder(
InfoResource.class,
new ArrayList<ResourceModelIssue>()
);
// bind it to "info" path
rb.path("info");
// add it to the resource config
this.addResources(rb.build());
}
}
Add the Jersey 1.x version of the same class into the com.example.jersey1 package. It should look as follows:
package com.example.jersey1;
import com.sun.jersey.api.core.PackagesResourceConfig;
// extend PackagesResourceConfig to get the package scanning functionality
public class ExampleResourceConfig extends PackagesResourceConfig {
public ExampleResourceConfig() {
// pass name of the package to be scanned
super("com.example");
// add InfoResource as an explicit resource bound to "info" path
this.getExplicitRootResources().put("info", InfoResource.class);
}
}
Adding Link to InfoResource to the index.jsp
To be able to conveniently access the InfoResource, let’s add a link to the index.jsp page. Here is how the updated index.jsp looks like:
And finally we will use the PortableServletContainer to put this all together. Open web.xml and replace the use of ServletContainer with the use of PortableServletContainer. It will have two sets of init-parameters – one Jersey 1.x specific – prefixed with jersey1#, the other one Jersey 2.0 specific prefixed with jersey2#. The servlet will figure out automatically what version of Jersey runtime is present and use the right init-params subset. Btw, obviously you don’t have to add jersey1/2# prefix to the parameter name if that parameter should be present and have the same value regardless of Jersey version being used. Here is how the updated web.xml should look like:
Jersey Web Applicationorg.glassfish.jersey.servlet.portability.PortableServletContainerjersey1#javax.ws.rs.Applicationcom.example.jersey1.ExampleResourceConfigjersey1#example.textUsing Jersey 1.xjersey2#javax.ws.rs.Applicationcom.example.jersey2.ExampleResourceConfigjersey2#example.textUsing Jersey 2.01Jersey Web Application/webapi/*
Trying It Out
Now you can build the application and deploy the war to GlassFish 3.1.2 which bundles Jersey 1. Assuming the GlassFish is running at locahost:8080, you should be able to access the application at http://localhost:8080/simple-service/. You can see that clicking on Jersey resource works (invokes MyResource.getIt() method returning “Got it!”) and clicking on InfoResource shows “Using Jersey 1.x”.
If you deploy the same thing on the latest GlassFish 4.0 promoted build that bundles Jersey 2, you should see that after clicking on InfoResource, “Using Jersey 2.0” is displayed.
While working full speed on Jersey 2.0, we are trying to be as transparent as possible. The JAX-RS itself is run in a transparent way – everybody can see the EG discussions by subscribing to users@jax-rs-spec.java.net or browsing the mailing list archives at http://jax-rs-spec.java.net. With Jersey 2.0 we are trying to track everything in the public Jersey JIRA – just click on the Agile tab and switch to the current milestone to see the planned tasks and the progress we are making.
One thing we haven’t been able to open up (due to firewall restrictions) is our internal code review process. We are using Gerrit to review every commit that goes into the public repository. We have hooks set up for the internally hosted Hudson to kick in for each review request and automatically verify that the proposed commit does not break the build if approved. All works great, but unfortunately isn’t available for external checkins (all checkins have to go through the internal Gerrit Git repository and only Gerrit pushes the changes to java.net once they are approved).
So, to make things more transparent and easier (and inviting) for potential external contributors, and people who want to keep an eye on what’s going on, I’ve been playing lately with making the Jersey 2.x sources available on GitHub as well. We’ve managed to set up a 3-way synchronization between GitHub, Gerrit and java.net which turns the GitHub Jersey 2.x workspace mirror into the first class citizen. The recently announced BuildHive free service from CloudBees helped to supply the pull request verification, so we are now able to handle GitHub pull requests in a similar way to our internal Gerrit review requests. While we will most likely still continue using our internal set-up to do the internal code reviews (due to better performance and integration with internal tools), we are now able to handle external pull requests in a nice manner. So you are now free to follow and/or fork Jersey on GitHub and eventually submit patches as pull request. Here is the link: http://github.com/jersey/jersey
Just remember, for us to be able to accept your contributions, you need to send in a signed OCA.
UPDATE (7/3/2012): Proxy-client module is now part of the regular workspace (instead of incubator) and get’s pushed to maven along with other Jersey modules, so no need to build it manually anymore.
Several JAX-RS 1.x implementations are providing proxy client API as one of the ways to access web services. The basic idea is you can attach the standard JAX-RS annotations to an interface, and then implement that interface by a resource class on the server side while reusing the same interface on the client side by dynamically generating an implementation of that using java.lang.reflect.Proxy calling the right low-level client API methods.
Jersey 1.x client API (and now JAX-RS 2.0 client API) leverages the fact REST (and HTTP) defines the standard set of operations, so unlike for JAX-WS type of web services, which are verb-centric, for RESTful web services the interface is uniform and thus there is no need for generating client proxies. The standard client API is static (has fixed set of operations – get, put, post, delete, …). Proxy client API may be seen as evil, as it creates tighter coupling between services and clients. However, some people do find it useful and it provides better opportunities for reusing JAX-RS concepts between services and clients, including name-bound interceptors, for example.
Few weeks back I quickly “hacked” a proxy client factory for Jersey as part of Jersey 2.0 and made some small incremental improvements since then. It is based purely on the current draft of the standard JAX-RS 2.0 client API, so should be usable with any JAX-RS 2.0 implementation, not just Jersey. Currently it lives in the “incubator” subfolder of Jersey 2.0 workspace, so if you want to give it a try, you have to check it out and build it yourself. The project includes a test that illustrates the usage, and also a simple example.
Building the Proxy-Client Project
To build it, first clone the Jersey repository, build Jersey, then switch to the proxy-client folder and build the proxy-client project. The following shell commands do that (assuming you have git and mvn installed):
git clone ssh://[your-java.net-user-id]@git.java.net/jersey~code jersey
cd jersey
mvn install
cd incubator/proxy-client
mvn install
Using/Playing with the Proxy-Client
The project has just one class – WebResourceFactory. Here is how it can be used:
Let’s say you want to access a web resource available at a URI that could be represented by the following URI template:
http://acme.com/rest/books/{book-id}
Let’s assume this resource can produce and consume application/json and application/xml and supports GET, PUT and DELETE operations. There is also a parent resource – http://acme.com/rest/books/ which accepts GET (returns a list of books) and POST (creates a new book). Here is one example of how you can model it using the interfaces with JAX-RS annotations and then access these resources using those interfaces and WebResourceFactory class:
public interface BookResource {
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
Book get();
@PUT
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
Book update(Book book);
@DELETE
void delete();
}
Accessing it from your application:
// create a new JAX-RS 2.0 target pointing to the root of the web api
Target t = ClientFactory.newClient().target("http://acme.com/rest/");
// create a new client proxy for the BooksResource
BooksResource booksRsc = WebResourceFactory(BooksResource.class, t);
// get list of books
List<Book> books = booksRsc.getBooks();
// get book resource by ID
BookResource bookRsc = booksRsc.getBookResource(bookId);
// get book object
Book myBook = bookRsc.get();
// delete book
bookRsc.delete();
I hope you got the idea. As you can see, the proxy factory can handle path parameters and can automatically create proxies for sub-resources. It can also handle other kinds of parameters such as header parameters, query parameters, form parameters and cookie parameters.
Over the past two weeks, I’ve been working with Pavel on finalizing and staging the bits for the hands-on-lab on OAuth, we are going to do at this year’s JavaOne. As part of that, I had to make a few more clean-ups in the Jersey OAuth client library, so we decided to make a branch for 1.9.1 and make those clean-ups along with some other small fixes there. Now, 2 weeks after 1.9, we released it. This is the release we’ll be using for JavaOne and although the release cycle was so short, it does have two nice additions worth highlighting.
Un-/marshalling collection types
Until 1.9.1, JAXB un-/marshalling in Jersey worked only for Collection and List interfaces. I.e. if your resource method returned (or took as a parameter) Collection<Foo> or List<Foo> (where Foo was a JAXB bean), de-/serialization from/to XML/JSON would work, but if it returned LinkedList<Foo> or Set<Foo> or any other Collection subtype, it would not work. This is fixed in 1.9.1 and you can now return and retrieve any well-known interfaces that extend Collection (such as Set, Queue, etc.) and their implementations which have default public constructor.
PostReplaceFilter improvements PostReplaceFilter can be used to support clients which can’t send the full range of HTTP methods. It enables converting POST requests to other methods such as PUT or DELETE. If a POST request comes with a different method specified in X-HTTP-Method-Override header, the filter will replace POST in the request with that specified method. This has been in Jersey for a while, but only supported method overriding using the X-HTTP-Method-Override header. In 1.9.1 you can now use “_method” query parameter as well, and when overriding POST to GET the filter will convert all the form parameters to query parameters. Whether both header and query parameter are looked at by the filter (or only the header or only the query parameter) is configurable. Thanks to gk5885, Fredy Nagy and Florian Hars for sharing their views and patches.
About two weeks back we released Jersey 1.9. See Jakub’s blog for more info on what’s new. One thing Jakub didn’t mention is that Jersey 1.9 also includes a new server side filter for Cross Site Request Forgery prevention. I won’t go into the details on what CSRF is – please refer to the OWASP CSRF page for that. Unfortunately, the generally recommended prevention is to generate per-request or per-session tokens on the server side, which client then has to include in its subsequent requests. This is quite easy to implement and there are servlet filters for doing that, however it does require a session state to be maintained and thus is not very RESTful. I was trying to implement something that would not require a session. After some searching I found the following two papers which both suggest there is a solution which works, and is not based on sessions:
The main idea is to check the presence of a custom header (agreed-upon between the server and a client – e.g. X-CSRF or X-Requested-By) in all state-changing requests coming from the client. The value of the header does not really matter. It works, because the browser would not send custom headers unless the web page makes a request using XMLHttpRequest, which only allows requests to the same site.
And, to make it easy to build clients, a corresponding client filter (that attaches the custom header to all potentially state-changing requests) is there as well: client-side CsrfProtectionFilter.
This can be further extended based on the feedback – we may add a check for the Referrer header and eventually even implement the session-based solution as an available configuration option. Just let us know, if you have an opinion.
Earlier this year, me and Naresh created an introductory level Jersey hands-on lab for JavaOne ’09. As I realized just recently, the hands-on labs had been made available for download to all SDN members (free registration) shortly after JavaOne. It may be another useful resource for you to get started with Jersey. The lab provides detailed step-by-step instructions on how to set up your environment and then guides you through 3 exercises:
Hello world! – leading you through your first JAX-RS/Jersey application, explaining the JAX-RS basics
Advanced JAX-RS/Jersey Features – showing how to develop a little more complex web application using JAX-RS/Jersey features such as path parameters, multiple representations for a resource, writing your own MessageBodyReader/Writer, Jersey MVC and some more
Using Jersey Client API – showing how to access web resources using the Client API provided by Jersey
You can download the Hands-On Lab as well as get more info here. I’ve also added this link to our Jersey Wiki. After you download the lab, just unzip the file and open index.html in restwebservice directory. The zip also contains solution directories for all three exercises. I hope the lab will be of help. Let me know in case you have any questions or feedback on it.
Over the past week I’ve been playing a bit with JavaFX. I will blog on my experience later. Today I would like to follow up on my last post and write about the OAuth callback.
If you look at the sample code in my last blog, there is one ugly thing – users have to be told to press Enter once they authenticate in a browser that the application opens:
// open the browser at the authorization URL to let user authorize
Desktop.getDesktop().browse(new URI(URL_AUTHORIZE +
"?oauth_token=" + response.auth.token.id));
// wait for the user to authenticate
System.out.println("Once you authenticated with SmugMug and granted" +
"permissions to this app, press Enter to continue.");
System.in.read();
Although the OAuth specification mentions one can pass a callback URL to the authorization call, I had not been able to make it work with SmugMug until recently, when I ran into this post on the SmugMug API forum. The post says that instead of accepting the oauth_callback as the query parameter in the authorization request, SmugMug allows me to set the callback URL for my application by editing the properties of the API key I’ve received in the SmugMug control panel. So, I went ahead and tried to set it to “http://localhost:9097/oauth” and it worked! So I was able to get rid of that ugly waiting for users pressing the Enter key with the following trick:
synchronized (App.class) {
// create an instance of the lightweight HTTP server on port 9097
HttpServer server = HttpServer.create(new InetSocketAddress(9097), 0);
// assign a handler to "/oauth" context
server.createContext("/oauth", new HttpHandler() {
public void handle(HttpExchange t) throws IOException {
// notify the app the user has authorized
synchronized (App.class) {
App.class.notifyAll();
}
// send some descriptive page as a response
t.sendResponseHeaders(200, 0);
OutputStream os = t.getResponseBody();
InputStream is = getClass().getResourceAsStream("authorize.html");
int count;
byte[] b = new byte[32000];
while (0 < (count = is.read(b))) {
os.write(b, 0, count);
}
// close the streams
os.close();
is.close();
}
});
server.setExecutor(null); // creates a default executor
// start the server
server.start();
// open the authorization URI in the browser
Desktop.getDesktop().browse(new URI(URL_AUTHORIZE +
"?oauth_token=" + response.auth.token.id));
// wait until the HttpHandler sends me "notify" signal
App.class.wait();
// user has authorized - stop the lightweight HTTP server
server.stop(0);
}
Basically, just before I send a request to the authorization URI, I start an instance of the lightweight HTTP server (present in JDK6 or you can download it here in case you are running on JDK5) which listens on http://localhost:9097/oauth, and then just wait for the callback request to come in. SmugMug, once the user authorizes, redirects the browser to this URL, which wakes up the suspended execution of my app and returns some descriptive HTML page to the user - something along the same lines as the original SmugMug page, e.g.:
Thank you for adding App to your Authorized Applications.
(You can de-authorize anytime via your control panel.)
Now, one drawback of the SmugMug approach of not allowing applications to specify the callback URL dynamically (in the request to the authorization URL) is that the port your application uses is pretty much hard-coded - you have to manually enter it (as part of the callback URL) in your API key properties on SmugMug website. That means, if the port your application wants to use is busy you have to fall back to the original approach.
Recently I decided to use SmugMug to store my photo galleries. They have an API people can use to access the features of the site programmatically and I noticed they added OAuth in the latest version. So, I thought I would give it a try and see if I can use the OAuth Support in Jersey to authorize and authenticate my client application with SmugMug. Turned out it works! Here is how to do it:
First you have to request an API Key from SmugMug. You can do it here.
They probably approve these automatically – mine was approved immediately and I got the key along with a “secret” (another number used as a consumer secret key in OAuth).
Now you can create a new maven project, adding jersey-client, jersey-json, oauth-signature and oauth-client as the dependencies – here is a pom file snippet:
The first thing you need to do according to the OAuth spec is to get an unauthorized request token from the provider (SmugMug in this case). You will need the key and the secret you obtained in step 1. The SmugMug API provides a method for requesting these tokens – getRequestToken. Here is an example of how you can call this method using Jersey client API and the Jersey OAuth library:
public class App {
// base URL for the API calls
private static final String URL_API =
"http://api.smugmug.com/services/api/json/1.2.2/";
private static final String CONSUMER_SECRET = /* your API Key */;
private static final String CONSUMER_KEY = /* your secret key */;
public static void main( String[] args ) throws Exception {
// Create a Jersey client
Client client = Client.create();
// Create a resource to be used to make SmugMug API calls
WebResource resource = client.resource(URL_API).
queryParam("method", "smugmug.auth.getRequestToken");
// Set the OAuth parameters
OAuthSecrets secrets = new OAuthSecrets().consumerSecret(CONSUMER_SECRET);
OAuthParameters params = new OAuthParameters().consumerKey(CONSUMER_KEY).
signatureMethod("HMAC-SHA1").version("1.0");
// Create the OAuth client filter
OAuthClientFilter filter =
new OAuthClientFilter(client.getProviders(), params, secrets);
// Add the filter to the resource
resource.addFilter(filter);
// make the request and print out the result
System.out.println(resource.get(String.class));
}
}
The next step in the OAuth flow is to obtain user authorization. To do this, the user needs to be redirected to the SmugMug authorization URL – http://api.smugmug.com/services/oauth/authorize.mg (see the SmugMug Specifics section on their OAuth page), passing the request token ID as a query parameter (you need to extract that from the getRequestToken method’s response). At this URL the user will log in and grant the requested access to your application. Here is how I did it:
public class App {
// base URL for the API calls
private static final String URL_API =
"http://api.smugmug.com/services/api/json/1.2.2/";
// authorization URL
private static final String URL_AUTHORIZE =
"http://api.smugmug.com/services/oauth/authorize.mg";
private static final String CONSUMER_SECRET = /* your API Key */;
private static final String CONSUMER_KEY = /* your secret key */;
public static void main( String[] args ) throws Exception {
// Create a Jersey client
Client client = Client.create();
// Create a resource to be used to make SmugMug API calls
WebResource resource = client.resource(URL_API).
queryParam("method", "smugmug.auth.getRequestToken");
// Set the OAuth parameters
OAuthSecrets secrets = new OAuthSecrets().consumerSecret(CONSUMER_SECRET);
OAuthParameters params = new OAuthParameters().consumerKey(CONSUMER_KEY).
signatureMethod("HMAC-SHA1").version("1.0");
// Create the OAuth client filter
OAuthClientFilter filter =
new OAuthClientFilter(client.getProviders(), params, secrets);
// Add the filter to the resource
resource.addFilter(filter);
// make the request
RequestTokenResponse response = resource.get(RequestTokenResponse.class);
// check the status
if (!"ok".equals(response.stat)) {
System.out.println("getRequestToken failed with response: " +
response.toString());
return;
}
// open the browser at the authorization URL to let user authorize
Desktop.getDesktop().browse(new URI(URL_AUTHORIZE +
"?oauth_token=" + response.auth.token.id));
}
}
The RequestTokenResponse class representing getRequestToken method’s response looks as follows:
@XmlRootElement
public class RequestTokenResponse {
public String stat;
public String method;
public @XmlElement(name="Auth") AuthElement auth;
public static class AuthElement {
public @XmlElement(name="Token") TokenElement token;
@Override
public String toString() {
return "token=(" + (token == null ? "null" : token.toString()) + ")";
}
}
public static class TokenElement {
public String id;
public @XmlElement(name="Secret") String secret;
@Override
public String toString() {
return "id=" + id + " secret=" + secret;
}
}
@Override
public String toString() {
return "stat=" + stat + " method=" + method + " auth=(" +
(auth == null ? "null" : auth.toString()) + ")";
}
}
After the user authenticates and grants access for your application, the last step is to request an access token – that will then enable your application to make subsequent API calls. You can implement this by adding the following lines at the end of the main method from the previous bullet:
// wait for the user to authenticate
System.out.println("Once you authenticated with SmugMug and granted" +
"permissions to this app, press Enter to continue.");
System.in.read();
// make an API call to request the access token
resource = client.resource(URL_API).queryParam("method",
"smugmug.auth.getAccessToken");
// use the request token id and secret to create the request
secrets.setTokenSecret(response.auth.token.secret);
params.token(response.auth.token.id);
resource.addFilter(filter);
// make the request and print out the result
System.out.println(resource.get(String.class));
That’s it! Now your application can store the access token and use it to perform actions on behalf of the user.