samedi 3 mai 2014

Random resources related to Docker

General


Management


Continuous Integration

Environment configuration
DevOps

lmctfy

Networking

Ecosystem
  • Atomic project - Deploy and Manage your Docker Containers 
  • GearD - The Intersection of PaaS, Docker and Project Atomic 
  • Classification of the ecosystem of startups based on Docker 
  • Slides from DockerFr Meetup on Docker ecosystem
  • OpenCore a Big Data (Hadoop) as a Service provider


API Client
work in progress

dimanche 13 avril 2014

Managing Docker images and containers

In addition to managing Docker resources (including containers, images, hosts) through the official CLI, there is plenty of solutions available in the community to manage Docker resources in a comprehensive way from a single web-based interface.

DockerUI

Once our containers are running, DockerUI can be use to manage the overall system. It's a simple web app with basic features for:
 - Check the states of the images (running, stopped)
 - Remove images
 - Start, Stop, Kill and Remove containers

DockerUI can be used with the following commands

1. Building the web app from the github repository and tag the build image
$docker build -t crosbymichael/dockerui github.com/crosbymichael/dockerui

2. Launch the built container, make the web app available on the 9000 port and connect to the docker uinx socket to remotely control docker
$docker run -p 9000:9000 -v /var/run/docker.sock:/docker.sock crosbymichael/dockerui -e /docker.sock

Then on the browser, visit localhot:9000 to get something like:

Shipyard

Shipyard is a more advanced Docker management solution based on a client-server architecture where the agents (i.e. clients) collect information on Docker resources and report them to the Shipyard server. It providers in addition to the features available in DockerUI:
 - Authentication
 - Building new images by uploading local Dockerfile or providing URLs to a remote location
 - In the browser terminal emulation for attaching containers
 - Visualizing CPU and memory utilization of the running images
 - ...

1. To use Shipyard, issue to pull the image from the Docker public index:
$docker run -i -t -v /var/run/docker.sock:/docker.sock shipyard/deploy setup

Now, we can register as admin to Shipyard on http://localhost:8000/

2. Install the latest release (e.g. v0.2.5) of Shipyard agent on every hosts to collect the information on Docker resources:
$curl https://github.com/shipyard/shipyard-agent/releases/download/v0.2.5/shipyard-agent -L -o /usr/local/bin/shipyard-agent
$chmod +x /usr/local/bin/shipyard-agent

3. Run the agent and register to the main host where Shipyard is running
$/usr/local/bin/shipyard-agent -url http://localhost:8000 -register

4. On the Shipyard interface, authorize the agents already deployed to enable them.
5. Run the agent with the given key at registration:
$/usr/local/bin/shipyard-agent -url http://localhost:8000 -key agent_key



Troubleshooting, in case you get this message:
Error requesting images from Docker: Get http://127.0.0.1:4243/images/json?all=0
Then stop the Docker service and re-start it while enabling Remote API access for any IP address:
$sudo service docker stop
$docker -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock -d &

happy dockering

dimanche 6 avril 2014

Automating Docker image builds with Dockerfiles

Hello Dockerfile
This is a continuation of an previous post on Docker with the aim of using specific scripts called dockerfiles in order to automate the steps that we have been issuing to build docker images. When docker parse the script file, it sequentially executes the commands starting from a base image to create a new one after each command.
The syntax of a dockerfile instruction is as simple as :
command argument1 argument2 ... 
or
command ["argument1", "argument2", ...]  only for the entry-point command !!

It's preferable to write the command in uppercase!

Dockerfile instructions
There is a dozen of instructions that can be present in a dockerfile, a detailed list can be found in the official documentation. The most common ones are:
  • FROM all dockerfile should start with this command that specify the name of the image to use as a working or base image;
  • RUN allows to run a command in the current container and commit (automatically) the changes to a new image;
  • MAINTAINER allows to specify information (name, email) on the person responsible for maintain this script;
  • ENTRYPOINT allows to specify what command should be executed at first once the container is started;
  • USER allows to specify with which user account the command inside the container have to be executed with; 
  • EXPOSE allows to specify what port to expose for the running container.
  • ENV to use for setting environment variables
  • ADD to copy files from the build context (it does not work if using stdin to read dockerfile) into a physical directory in the image (e.g. copying a war file into tomcat webapps folder)
Here you can find the official tutorial to experiment with these command.

Parsing dockerfiles
Once finished editing the build script, issue docker build to parse the dockerfile and create a new image. There is different ways to use this command:
  • dockerfile is in current directory docker build .
  • from stdin docker build - < Dockerfile
  • from a github repository docker build github.com/username/repo docker will then clone the repo and parse the files in the repo directory.

Example
Now lets take the instructions from the previous post and gather them into a dockerfile:
# Use ubuntu as a base image
FROM ubuntu

# update package respository
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list

RUN echo "deb http://archive.ubuntu.com/ubuntu precise-security main universe" > /etc/apt/sources.list
RUN apt-get update

# install java, tomcat7
RUN apt-get install -y default-jdk
RUN apt-get install -y tomcat7

RUN mkdir /usr/share/tomcat7/logs/
RUN mkdir /usr/share/tomcat7/temp/

# set tomcat environment variables
ENV JAVA_HOME=/usr/lib/jvm/default-java
ENV JRE_HOME=/usr/lib/jvm/default-java/jre
ENV CATALINA_HOME=/usr/share/tomcat7/

# copy war files to the webapps/ folder
ADD path/to/war /usr/share/tomcat7/webapps/

# launch tomcat once the container started
#ENTRYPOINT service tomcat7 start
ENTRYPOINT /usr/share/tomcat7/bin/catalina.sh run

# expose the tomcat port number
EXPOSE 8080

Save this script to Dockerfile, build it and tag the image by tomcat7, then launch the container while exposing publicaly the tomcat server port 8080, and finally check if the container is running
$docker build -t tomcat7 - < Dockerfile
$docker run -p 8080 tomcat7
$docker ps

to be continued;

lundi 31 mars 2014

Build your own SaaS with Docker - Part I

Hello Docker
Docker enables sand-boxing of applications and their dependencies in virtual containers to be able to run them in isolated mode. It provides an easy to use API for automating deployment operations that looks very close to Git commands. More introductory information can be found in its Wikipedia page.

Installation
Docker installation on a Ubuntu 64bit (for other OS check official documentation)
$sudo sh -c "curl https://get.docker.io/gpg | apt-key add -" 
$sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" 
$sudo apt-get update
$sudo apt-get install lxc-docker

Once docker installed, run a shell from within a container as follow
$sudo docker run -i -t ubuntu /bin/bash

As it is supposed to not find the ubuntu image, docker will pull it from the registry. Once, installed you can prompt:
  • #exit to leave the container
  • $sudo docker images to see all local images.
  • $sudo docker inspect image_name to see detailed information on an image.
  • $sudo docker ps to see the status of the container
  • $sudo docker stop CONTAINER_ID to stop a running image (or container)
  • $sudo docker logs CONTAINER_ID to see all logs if a given container
  • $sudo docker commit CONTAINER_ID image_name to commit changes made to a container

Installing Tomcat within a container
Start a new container using the ubuntu base image:
$sudo docker run -i -t ubuntu /bin/bash

Update the image's system packages
#apt-get update

1. Install the Apache Tomcat application server:
#apt-get install -y tomcat7

Once installed the following directories are created (more details can be found here):
  • /etc/tomcat7 for configuration
  • /usr/share/tomcat7 for runtime, called $CATALINA_HOME
  • /usr/share/tomcat7-root for webapps
2. Install Java DK
#apt-get install -y default-jdk

3. Configure environment variables
#pico ~/.bashrc
export JAVA_HOME=/usr/lib/jvm/default-java
export CATALINA_HOME=~/path/to/tomcat
#. ~/.bashrc to make the changes effective

Now when typing #echo $CATALINA_HOME you should see the exact path set to tomcat7.

4. Start the Tomcat7 server
#$CATALINA_HOME/bin/startup.sh
or
#service tomcat7 start

The start-up may fail with something like "cannot create directory '/usr/share/tomcat7/logs/catalina.out/'". To solve this, you may just have create the logs directory:
#mkdir /usr/share/tomcat7/logs

to check if Tomcat is running issue
#ps -ef | grep tomcat
or
#service tomcat7 status

then check in your browser http://container_ip_address:8080/
to get the IP address of the container issue
#ifconfig

5. Shutdown  Tomcat7
#$CATALINA_HOME/bin/shutdown.sh
or
#service tomcat7 stop

Save the image to index.docker.io
The changes we made on the base image created a new one, we should commit these changes to not lose these changes.

1. Login to index.docker.io
$sudo docker login
Username: your_user_name
Password: your_password
Email: your_email
Login Succeeded

If you don't have an account, sign up here.

2. Commit changes to your repository
$sudo docker commit CONTAINER_ID USERNAME/REPO_NAME

3. Push changes to this repository
$sudo docker push USERNAME/REPO_NAME

4. Start a new container using the image commit to your repository as base image
$sudo docker run -i -t USERNAME/REPO_NAME /bin/bash
#

To run Tomcat in the container
$sudo docker run -i -t USERNAME/REPO_NAME $CATALINA_HOME/bin/startup.sh
or
$sudo docker run -i -t USERNAME/REPO_NAME service tomcat7 start

to cleanup old containers
$sudo docker ps -a -q | xargs sudo docker rm
or
$sudo docker ps -a | awk '{print $1}' | xargs sudo docker rm

to cleanup old and non tagged images
$sudo docker images | grep "^" | awk '{print $3}' | xargs sudo docker rmi -f

Resources
If you are confused with docker terminology (e.g. container, image, etc.) check this official documentation.
General purpose instructions for installing Tomcat7 on a ubuntu machine here.

dimanche 6 octobre 2013

Joyn or RCS

RCS (Rich Communication Services) is a GSMA standard that aims to bring a set of rich communication (that goes beyond SMS and phone calls) yet inter-operable services  across different domains managed by different telecom operators. This telcos standard is marketed under the name of Joyn.
Many operators has already deployed on their networks offering users VoIP and presence services that can be accessed by installing an application from the market store (Google Play, AppStore). In addition, some smarphone manufacturers who have joined the movement already embed the RCS stack into their devices.

The next step of commercializing Joyn is to build an ecosystem by providing APIs and empowering the developers community to create communication-based applications that relies on the platform. Orange through Orange Partner and Deutsch Telekom through the Developer Garden programs are leading these efforts in Europe. For instance, they jointly sponsored the Joyn Hackathon (press release) were the Joyn API  was introduced.

The remaining of this post explains how to use the Android Joyn SDK to build conversational applications. The overall interaction between an application and the Joyn SDK (and behind the RCS platform) is explained in the following figure.
Joyn API call flow

  1. Instantiate Joyn service and establish a connection
   private ChatService mService;
   private JoynServiceListener mListener = new JoynServiceListener() {
      @Override public void onServiceDisconnected(int error) {
         Log.i(TAG, "ChatService disconnected!");
      }
      @Override public void onServiceConnected() {
         Log.i(TAG, "ChatService connected!");
      }
   };
   ...
   // Instanciate API
   mService = new ChatService(getApplicationContext(), mListener); 
   // Connect API
   mService.connect();
  1. When the the connection is successfully established then start calling API methods
   private Chat mChat;
   private ChatListener mChatListener = new ChatListener() {
      @Override public void onReportMessageFailed(String arg0) {}
      @Override public void onReportMessageDisplayed(String arg0) {}
      @Override public void onReportMessageDelivered(String arg0) {}
      @Override public void onNewMessage(ChatMessage arg0) {}
      @Override public void onComposingEvent(boolean arg0) {}
   };
   ...
   @Override public void onServiceConnected() {
      Log.i(TAG, "ChatService connected!");
      if (mService != null && mService.isServiceRegistered()) {
         // Get remote contact
         String contact = getIntent().getStringExtra("contact");
         // Call API Methods
         mChat = mService.openSingleChat(contact, mChatListener); 
         mChat.sendMessage("hello world!");
      }
   }
The API doc of the ChatService can be found on this link.

dimanche 9 juin 2013

Adding search capabilities to an Android application

To set up a search assistant in an application, you need to go through the following steps :
  • Define a searchable configuration: An XML file that configures some settings for the search dialog or widget. It includes settings for features such as hint text, search suggestion, voice search, etc.
  • A searchable activity that will receive the search query, to perform the search on the application data data, then to display the results.
  • A search interface, provided by either: a search dialog that will appear at the top of the screen when the user presses the device SEARCH button (if available), it can also called programmatically from the code, or a SearchView widget.
First, the XML searchable configuration res/xml/searchable.xml:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.fontself.sms.provider.ContactProvider"    
    android:searchSuggestIntentAction="android.intent.action.VIEW">
</searchable> 

Second, the ContentProvider that will be called by the Android system to perform search:
public class MyContentProvider extends ContentProvider {
   public static String AUTHORITY = "com.app.package.MyContentProvider";
   private static final int SEARCH_SUGGEST = 0;
   private static final int SHORTCUT_REFRESH = 1;
   private static final UriMatcher sURIMatcher = buildUriMatcher();

   private static final String[] COLUMNS = {
      "_id",  // must include this column
      SearchManager.SUGGEST_COLUMN_TEXT_1,
      SearchManager.SUGGEST_COLUMN_TEXT_2,
      SearchManager.SUGGEST_COLUMN_INTENT_DATA,     
   };
   private static UriMatcher buildUriMatcher() {
      UriMatcher matcher =  new UriMatcher(UriMatcher.NO_MATCH);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, SHORTCUT_REFRESH);
      matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", SHORTCUT_REFRESH);
      return matcher;
   }
   @Override public String getType(Uri uri) {
      switch (sURIMatcher.match(uri)) {  
      case SEARCH_SUGGEST:
         return SearchManager.SUGGEST_MIME_TYPE;
      case SHORTCUT_REFRESH:
         return SearchManager.SHORTCUT_MIME_TYPE;
      default:
         throw new IllegalArgumentException("Unknown URL " + uri);
      }
   }
   @Override public boolean onCreate() {  
      return false;
   }
   @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {  
      if (!TextUtils.isEmpty(selection)) {
         throw new IllegalArgumentException("selection not allowed for " + uri);
      }
      if (selectionArgs != null && selectionArgs.length != 0) {
         throw new IllegalArgumentException("selectionArgs not allowed for " + uri);
      }
      if (!TextUtils.isEmpty(sortOrder)) {
         throw new IllegalArgumentException("sortOrder not allowed for " + uri);
      }
      switch (sURIMatcher.match(uri)) {
         case SEARCH_SUGGEST:
            String query = null;
            if (uri.getPathSegments().size() > 1) {
               query = uri.getLastPathSegment().toLowerCase();
            }
            return getSuggestions(query, projection);
         case SHORTCUT_REFRESH:
            String shortcutId = null;
            if (uri.getPathSegments().size() > 1) {
               shortcutId = uri.getLastPathSegment();
            }
            return refreshShortcut(shortcutId, projection);
         default:
            throw new IllegalArgumentException("Unknown URL " + uri);
      }  
   }
   private Cursor getSuggestions(String query, String[] projection) {
      String processedQuery = query == null ? "" : query.toLowerCase();
      List<MyObject> rows = doSearch(processedQuery);
        
      MatrixCursor cursor = new MatrixCursor(COLUMNS);
      for (MyObject row : rows) {
          cursor.addRow(columnValuesOfWord(row));
      }        
      return cursor;
   }
   private Object[] columnValuesOfWord(MyObject obj) {
      return new String[] {
         obj._id,    // _id
         obj.name,   // text1
         obj.phone,  // text2
         obj.phone,  // intent_data (included in the Intent when clicking on item)
      };
   }
   private Cursor refreshShortcut(String shortcutId, String[] projection) {
      return null;
   }
    
   @Override public Uri insert(Uri uri, ContentValues values) {
      throw new UnsupportedOperationException();
   }

   @Override public int delete(Uri uri, String selection, String[] selectionArgs) {
      throw new UnsupportedOperationException();
   }

   @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
      throw new UnsupportedOperationException();
   }
}

Third, define the SearchActivity:
public class MySearchActivity extends ListActivity {
   public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
   //setContentView(R.layout.search);  
        setListAdapter(new MyAdapter.getInstance(MySearchActivity.this));
        handleIntent(getIntent());  
   } 

   @Override protected void onNewIntent(Intent intent) { 
      setIntent(intent); 
      handleIntent(intent);  
   } 

   public void onListItemClick(ListView l, View v, int position, long id) {       
      // call detail activity for clicked entry     
   } 

   private void handleIntent(Intent intent) {    
      if (Intent.ACTION_SEARCH.equals(intent.getAction())) {            
         // Handle the normal search query case
         String query = intent.getStringExtra(SearchManager.QUERY);            
         doSearch(query);       
      } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
         // Handle a suggestions click (because the suggestions all use ACTION_VIEW)
         Uri data = intent.getData();
         showResult(data);
      }
   }    
   
   private void showResult(Uri data) {}

   private void doSearch(String queryStr) {    
      // get a Cursor, prepare the ListAdapter and set it
   } 

}
Finally, update the AndroidManifest.xml file:
<application>
<meta-data android:name="android.app.default_searchable" android:value=".MySearchActivity" />
     <activity android:name=".MySearchActivity" android:label="@string/app_name" android:launchMode="singleTop" > 

<!-- enable the search dialog to send searches to MessageActivity -->       
         <intent-filter >
             <action android:name="android.intent.action.SEARCH" /> 
        </intent-filter> 
        <intent-filter > 
           <action android:name="android.intent.action.VIEW" /> 
        </intent-filter> 
        <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />

     </activity>
<provider android:name=".MyContentProvider" android:authorities="com.app.package.MyContentProvider" />
</application>

Resources

For more details check official documentation on ContentProvider, Search dialogs, how to implement custom suggestions, and how to use recent search suggestions. In case, you are using ActionBarSherlock check this blog post.
You may also have to check the SearchableDitionary sample project that comes with the Android SDK.

dimanche 19 mai 2013

Sample Android OAuth client

OAuth is the Internet protocol that gives you an authorized access to resources on the Internet without grating user credentials. It has been deployed by many services like Twitter, Google, Yahoo or LinkedIn. And there are some libraries / code snippet in most every programming language that implement OAuth, but it is still hard to get it work (at least on Android).
Here is a sample code snippets based on the Signpost library that uses a custom WebView to intercept HTTP calls and handle them.
First the OAuthHelper.java the helper class:
private Context mContext;
private OAuthConsumer mConsumer;
private OAuthProvider mProvider;
private String mCallbackUrl;
private SharedPreferences mSettings;
private OAuthListener mListener;

public OAuthHelper(Context context, String consumerKey, String consumerSecret) {
   if ((consumerKey == null || "".equals(consumerKey)) && (consumerSecret == null || "".equals(consumerSecret))) {
      throw new IllegalArgumentException("You must specify your \"consumer Key\" and your \"consumer Secret\" when instantiating a OAuthHelper object");
   }
   mContext = context;
   mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
   mProvider = new CommonsHttpOAuthProvider(QypeConstants.REQUEST_TOKEN_URL, QypeConstants.ACCESS_TOKEN_URL, QypeConstants.AUTHORIZE_URL);
   mProvider.setOAuth10a(true);
   mCallbackUrl = QypeConstants.REDIRECT_URI;
     
   mSettings = context.getSharedPreferences(QypeConstants.PREFS_NAME, 0);
}

public void authorize(OAuthListener listener) 
   throws OAuthMessageSignerException, OAuthNotAuthorizedException, OAuthExpectationFailedException, OAuthCommunicationException {

   mListener = listener;
   OAuthLoginDialog oauthDialog = new OAuthLoginDialog(mContext, this);
   oauthDialog.loadUrl(getRequestToken());
   oauthDialog.show();
}

public String getRequestToken() 
   throws OAuthMessageSignerException, OAuthNotAuthorizedException,
   OAuthExpectationFailedException, OAuthCommunicationException {
   String authUrl = mProvider.retrieveRequestToken(mConsumer, mCallbackUrl);
   return authUrl;  
}

public String[] getVerifier(String uriString) {       
   return getVerifier(Uri.parse(uriString));
}

public String[] getVerifier(Uri uri) {
   // extract the token if it exists     
   if (uri == null) {
      return null;
   }
   String token = uri.getQueryParameter("oauth_token");
   String verifier = uri.getQueryParameter("oauth_verifier");
   return new String[] { token, verifier };
}

public String[] getAccessToken() {
   String access_token = mSettings.getString(ACCESS_TOKEN, null);
   String secret_token = mSettings.getString(SECRET_TOKEN, null);
   if(access_token==null || secret_token==null)
      return null;
   return new String[] {access_token, secret_token};
}

public void getAccessToken(final String verifier) {
   new Thread(new Runnable() {   
      public void run() {
         try {
            mProvider.retrieveAccessToken(mConsumer, verifier);
            mSettings.edit().putString(ACCESS_TOKEN, mConsumer.getToken()).commit();
            mSettings.edit().putString(SECRET_TOKEN, mConsumer.getTokenSecret()).commit();
            mListener.onOAuthComplete();     
         }catch(Exception e) {            
            e.printStackTrace();
         }
      }
   }).run();
}

public String request(String url) {
   String content = null;
   try {
       String accessToken[] = getAccessToken();
       mConsumer.setTokenWithSecret(accessToken[0], accessToken[1]);   
       HttpGet request = new HttpGet(url);
       // sign the request
       mConsumer.sign(request);
       // send the request
       HttpClient httpClient = new DefaultHttpClient();
       HttpResponse response = httpClient.execute(request);   
       content = EntityUtils.toString(response.getEntity());
   } catch (Exception e) {
       e.printStackTrace(); 
   }
   return content;
}
Second, the OAuthLoginDialog.java that will be used to intercept HTTP call back url
public class OAuthLoginDialog extends Dialog {
   private WebView mWebView;
   private OAuthHelper mHelper;

   public OAuthLoginDialog(Context context, OAuthHelper helper) {
      super(context);
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      setContentView(R.layout.login_dialog);

      LayoutParams params = getWindow().getAttributes();
      params.height = LayoutParams.MATCH_PARENT;
      params.width = LayoutParams.MATCH_PARENT;
      getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);

      mHelper = helper;

      init();
   }
   private void init() {
      mWebView = (WebView) findViewById(R.id.webView);
      mWebView.getSettings().setJavaScriptEnabled(true);

      mWebView.setWebViewClient(new WebViewClient() {
         @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {}
         @Override public void onPageStarted(WebView view, String url, Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
             progressBar.setVisibility(View.VISIBLE);
             if(url.startsWith(REDIRECT_URI)) {
                if(mHelper.getAccessToken() == null) {
                   String[] token = mHelper.getVerifier(url);
                   mHelper.getAccessToken(token[1]);
                }     
                mWebView.clearCache(true);
                dismiss();
             } 
         }

         @Override public void onPageFinished(WebView view, String url) {
             super.onPageFinished(view, url);
             progressBar.setVisibility(View.GONE);
         }

      });

   }
 
   public void loadUrl(String url) {
      mWebView.loadUrl(url);
   }
}
Third, the OAuth listener interface
public interface OAuthListener {
   // Called when the user is logged to the server
   public void onOAuthComplete();
   // Called when the user has canceled the login process
   public void onOAuthCancel();
   // Called when the login process has failed
   public void onOAuthError(int errorCode, String description, String failingUrl);
}
Finally, this is the code used to initiate an OAuth connection
OAuthHelper mHelper = new OAuthHelper(mContext, API_KEY, API_SECRET);
mHelper.authorize(new OAuthListener() {    
   public void onOAuthError(int errorCode, String description, String failingUrl) {}
   public void onOAuthComplete() {
      String testUrl = "http://sample_url_for_oauth_authorization/";
      mHelper.request(testUrl)
   }    
   public void onOAuthCancel() {}
});  
More resources can be found here implementing client side OAuth for android (it uses intent filter instead of a custom dialog) and here a sample OAuth for twitter.

Get the code for a sample project on Github.