Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Using Twitter API ME for PIN-based authorization from Java ME

From Wiki
Jump to: navigation, search

This article explains how to use Twitter API ME to obtain Twitter access tokens through PIN-based authorization from a Java ME application.

Article Metadata
Code ExampleTested with
Devices(s): Nokia Asha 303, Nokia Asha 310
CompatibilityArticle
Keywords: Twitter, RecordStore, PIN-based authorization
Created: cadlg (17 Apr 2013)
Last edited: hamishwillee (27 Jun 2013)

Contents

Introduction

Twitter uses OAuth to provide authorized access to its API, which allows service providers to provide access to users’ data without requiring them to share their passwords with 3rd party applications.

However, the most common method for access authorization requires some kind of browser integration, since as part of the OAuth flow, the application needs to redirect the user to a Twitter page, and then redirect back to a URL under the application's control, which at the time of writing this article is not possible in Java ME.

For applications that cannot integrate a browser to complete the OAuth flow, Twitter offers the PIN-based authorization method, which is the one demonstrated in this article.

How does PIN-based authorization work?

In summary, the application starts the OAuth flow and at some point it opens a web browser with a Twitter page where the user has to log in to the service to authorize access for the application. Once the user has authorized the application, a number (called a PIN) is displayed in the browser, which the user needs to enter into the application’s authorization screen, which uses that PIN to complete the authorization process.

Prerequisites

To be able to test the code from this article, you need to have an application created on Twitter. If you need to create a new application, please go to https://dev.twitter.com/apps. (Details on how to create a new application on Twitter are out of the scope of this article).

You also need to have the Twitter API ME binaries on your development machine. If you need to download Twitter API ME, please go to the Twitter API ME downloads page. You can also use the binary libraries included in this article's downloadable example project.

Note.pngNote: The Twitter API ME license allows you to develop proprietary applications if you use the API’s binaries only (The API’s source code is released under a different license. See the licensing page)

Developing the example application

To demonstrate the authorization process we will create a very simple LWUIT application which after completing the authorization process will store the access token in a RecordStore to be able to use it in future executions, and will perform a simple Twitter search, whose results will be written to the console.

Note.pngNote: In Twitter API version 1 searches could be performed anonymously, but in version 1.1 every Twitter API call requires authentication, including searches.

Note that the example application does not show any progress indicator and to simplify the example it does not perform the tweets search in a separate thread.

Most of the application’s code is included and explained here, but to make sure you don’t miss anything, please download the accompanying zip file, which includes the test project (in Eclipse/Nokia IDE format).

As first step please create a new MIDlet project, add the LWUIT libraries and create a new blank MIDlet.

Tip.pngTip: If you need help accomplishing this step, please refer to the “Getting started” section of the LWUIT Developer’s library.

Next, we need to add the Twitter API ME libraries. Please add the following libraries (which should have been included in your Twitter API ME download) in the same way you added the LWUIT libraries:

  • twitter_api_me
  • json-me
  • kxml2-min


The name of the jar files may vary depending on the versions being used. In this case we have added the following jars to the example application:

  • twitter_api_me-1.8.jar
  • json-me.jar
  • kxml2-min-2.3.0.jar


Next, we need to add the necessary imports:

// For the persistent storage management
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
 
// For the UI
import com.sun.lwuit.Form;
import com.sun.lwuit.Label;
import com.sun.lwuit.Button;
import com.sun.lwuit.Display;
import com.sun.lwuit.TextArea;
import com.sun.lwuit.TextField;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.layouts.BoxLayout;
import com.sun.lwuit.Command;
 
// For Twitter access
import impl.javame.com.twitterapime.xauth.ui.MIDletOAuthDialogWrapper;
import com.twitterapime.rest.Credential;
import com.twitterapime.rest.UserAccountManager;
import com.twitterapime.search.Query;
import com.twitterapime.search.SearchDevice;
import com.twitterapime.search.Tweet;
import com.twitterapime.xauth.Token;
import com.twitterapime.xauth.ui.OAuthDialogListener;

Next, we will define some needed member variables and build the user interface in the MIDlet’s startApp() method:

	private Label label;
private TextArea textArea = null;
private Button button;
 
private Token accessToken;
private MIDletOAuthDialogWrapper pageWrapper;
 
private boolean PINrequested = false;
private String strToken;
private String strSearchCriteria;
private RecordStore recordStore;
 
...
 
Display.init(this);
Form form = new Form("Twitter Test");
form.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
 
label = new Label ("Enter search term");
form.addComponent(label);
 
// The textArea will be used to enter the search term
// and to enter the PIN (when authorizing access)
textArea = TextField.create();
form.addComponent(textArea);
 
// The button will be used to perform the search
// and to send the PIN to Twitter, to complete
// the authorization process
button = new Button("Search");
form.addComponent(button);
form.show();
 
//add exit command
Command exitCommand = new Command("Exit") {
public void actionPerformed(ActionEvent e) {
notifyDestroyed();
}
};
form.addCommand(exitCommand);
form.setBackCommand(exitCommand);

Now, we write methods to store and retrieve the access token to/from the record store:

	protected void storeToken(String token){
try {
recordStore = RecordStore.openRecordStore("tk", true);
int recId; // returned by addRecord but not used
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(baos);
try {
// Push the token into a byte array.
outputStream.writeUTF(token);
}
catch (IOException ioe) {
System.out.println(ioe);
ioe.printStackTrace();
}
// Extract the byte array
byte[] b = baos.toByteArray();
// If the record store is empty, we add a new record
if (recordStore.getNumRecords()==0)
{
try {
recId = recordStore.addRecord(b, 0, b.length);
}
catch (RecordStoreException rse) {
System.out.println(rse);
rse.printStackTrace();
}
}
// Otherwise, we update the existing record
else
{
try {
recordStore.setRecord(1,b,0,b.length);
}
catch (RecordStoreException rse) {
System.out.println(rse);
rse.printStackTrace();
}
}
try{
recordStore.closeRecordStore();
}
catch (RecordStoreException rse){
System.out.println(rse);
rse.printStackTrace();
}
}
catch (RecordStoreException rse) {
System.out.println(rse);
rse.printStackTrace();
}
}
 
protected String retrieveToken(){
String token = null;
try {
recordStore = RecordStore.openRecordStore("tk", true);
// If the record store is empty, return null
if (recordStore.getNumRecords()==0)
return null;
// Otherwise we read the token
else
{
ByteArrayInputStream bais = new ByteArrayInputStream(recordStore.getRecord(1));
DataInputStream inputStream = new DataInputStream(bais);
try {
token = inputStream.readUTF();
}
catch (EOFException eofe) {
System.out.println(eofe);
eofe.printStackTrace();
}
catch (IOException ioe) {
System.out.println(ioe);
ioe.printStackTrace();
}
}
recordStore.closeRecordStore();
}
catch (RecordStoreException rse) {
System.out.println(rse);
rse.printStackTrace();
}
return token;
}

Now we need to modify the MIDlet to implement the OAuthDialogListener interface and add some code to authorize the application when the record store is empty (which means that the application has not been authorized before).

So, the MIDlet should be declared like this:

public class TestMIDlet extends MIDlet implements OAuthDialogListener{
 
...
 
public void onAuthorize(Token accessToken) {
Credential c = new Credential(CONSUMER_KEY, CONSUMER_SECRET, accessToken);
UserAccountManager uam = UserAccountManager.getInstance(c);
try {
if (uam.verifyCredential()) {
//Store the access token
this.accessToken = accessToken;
strToken = accessToken.getToken();
storeToken(strToken);
search();
}
} catch (Exception e) {
System.out.println("Error when verifying credentials: " + e.getMessage());
}
}
 
public void onAccessDenied(String message) {
System.out.println("Access denied!");
}
 
public void onFail(String error, String message) {
System.out.println("Error when authenticating user: " + error + ", message:"+ message);
}

We also need to add some code to initialize the OAuth dialog wrapper object. Add this code at the beginning of the startApp() method:

        pageWrapper = new MIDletOAuthDialogWrapper(this);
pageWrapper.setConsumerKey(CONSUMER_KEY);
pageWrapper.setConsumerSecret(CONSUMER_SECRET);
pageWrapper.setOAuthListener(this);

Now we need to add an action listener for our button. We do this in the startApp() method.

Note that the same button is used to perform different actions. See the comments in the code, for a better understanding of how and when the OAuth process is started.

        button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// The button starts/continues the authorization process
// or performs the search, depending on the current
// contents of the strToken member variable
if (strToken == null)
{
if (!PINrequested)
{
strSearchCriteria = textArea.getText();
// Starts the authorization process
pageWrapper.login();
label.setText("Enter PIN");
button.setText("Send PIN");
textArea.setText("");
textArea.repaint();
PINrequested = true;
}
else
{
// Continues the authorization process using the PIN
pageWrapper.login(textArea.getText());
label.setText("Enter search term");
button.setText("Search");
textArea.setText(strSearchCriteria);
textArea.repaint();
}
}
else
search();
}
});

And finally we need to implement the methods needed to perform the search:

	public void searchTweets(String exact){
try{
SearchDevice s = SearchDevice.getInstance();
// Number of tweets to return=25, language=en, type=recent tweets
Query q = new Query("rpp=25&lang=en&phrase="+exact+"&result_type=recent");
Tweet[] twts = null;
if(q != null)
twts = s.searchTweets(q);
else
System.out.println("Query not constructed");
for (int i=0; i<twts.length;i++)
System.out.println(i + "):" + twts[i]);
System.out.println("number of tweets received: " + twts.length);
}
catch (Exception e){
System.out.println(e);
e.printStackTrace();
}
}
 
protected void search(){
if (strToken != null)
searchTweets(textArea.getText());
}

Summary

In summary, this is how the application accomplishes its goal:

  1. Calls the pageWrapper.login() method to start the authorization process.
  2. When the user enters the PIN received from Twitter, it calls the pageWrapper.login(PIN) method to continue the authorization process.
  3. When the onAuthorize() method is called, it creates a credential consisting of the consumer key, consumer secret and the access token it received from Twitter, and verifies it. If the credential is verified, it stores the access token.
  4. With the access token the application is allowed to interact with Twitter, in this case, it performs a simple search.

Source Code

A zip file containing the project for the application created for this article can be downloaded here: TwitterAPIME Test.zip

This page was last modified on 27 June 2013, at 03:40.
241 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×