Milan has posted 4 posts at DZone. View Full User Profile

SmugMug Client in Java with NetBeans IDE

06.03.2010
| 12099 views |
  • submit to reddit
Recently I wrote about the OAuth Support in NetBeans IDE 6.9. The sample showed the creation of a Java client for Twitter REST services, which are registered in the IDE by default. This is another sample showing how the popular SmugMug services can be registered in the IDE and used to create client applications. Note that SmugMug 1.2.2 uses, like Twitter, the OAuth 1.0 authentication mechanism.

Though the OAuth 1.0 is a standard security protocol and the OAuth authentication consists of 3 standard steps (1. get request_token, 2. authorization, 3. get access_token) there are differences in particular implementations. The differences are for example:

  • the URL used to obtain request_token and access_token strings
  • the HTTP methods and HTTP parameters used to get request_token and access_token
  • the Authorization URL (the URL where user grants the appliction to access user data)

NetBeans tries to contain such differences and specifies the XML Schema for the OAuth Metadata that can be used to describe the particular OAuth details.The OAuth Metadata can be included into WADL file, that is a SUN standard for descriping REST resources.

This is a sample WADL file for SmugMug services that can be used to register SmugMug in NetBeans IDE 6.9:

<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xsi:schemaLocation="http://research.sun.com/wadl/2006/10
https://wadl.dev.java.net/wadl20061109.xsd
http://netbeans.org/ns/oauth/metadata/1
http://netbeans.org/ns/oauth/metadata/1.xsd"
xmlns="http://research.sun.com/wadl/2006/10">
<grammars>
<oauth:metadata xmlns:oauth="http://netbeans.org/ns/oauth/metadata/1" base-url="http://api.smugmug.com/services/api/json/1.2.2/" signature-method="HMAC_SHA1">
<oauth:flow>
<oauth:request-token method-name="smugmug.auth.getRequestToken" request-style="QUERY" response-style="JSON" />
<oauth:authorization>
<oauth:fixed-url url="http://api.smugmug.com/services/oauth/authorize.mg"/>
<oauth:param oauth-name="oauth_token"/>
</oauth:authorization>
<oauth:access-token method-name="smugmug.auth.getAccessToken" request-style="QUERY" response-style="JSON" verifier="false"/>
</oauth:flow>
<oauth:param oauth-name="oauth_token" xpath="$Auth.Token.id"/>
<oauth:param oauth-name="oauth_token_secret" xpath="$Auth.Token.Secret"/>
</oauth:metadata>
</grammars>
<resources base="http://api.smugmug.com/services/api/json/1.2.2/">
<resource path="/">
<method name="GET" id="smugmug_albums_get">
<request>
<param name="method" fixed="smugmug.albums.get" type="xsd:string" style="query" required="true"/>
<param name="Empty" type="xsd:boolean" style="query"/>
<param name="Extras" type="xsd:string" style="query"/>
<param name="Heavy" type="xsd:boolean" style="query"/>
<param name="NickName" type="xsd:string" style="query"/>
<param name="Pretty" type="xsd:boolean" style="query"/>
<param name="Strict" type="xsd:boolean" style="query"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method name="GET" id="smugmug_images_get">
<request>
<param name="method" fixed="smugmug.images.get" type="xsd:string" style="query" required="true"/>
<param name="AlbumID" type="xsd:integer" style="query" required="true"/>
<param name="AlbumKey" type="xsd:string" style="query" required="true"/>
<param name="Empty" type="xsd:boolean" style="query"/>
<param name="Extras" type="xsd:string" style="query"/>
<param name="Heavy" type="xsd:boolean" style="query"/>
<param name="Pretty" type="xsd:boolean" style="query"/>
<param name="Strict" type="xsd:boolean" style="query"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>mID
</resources>
</application>

Note the oauth:metadata element, which describes specific parameters for OAuth authoriztion, like :

  • oauth:metadata: base-url : the URL where a SmugMug application should ask for OAuth 1.0 tokens
  • oauth:request-token: method-name HTTP GET method parameter name for accessing request_token
  • oauth:access-token: method-name HTTP GET method parameter name for accessing request_token
  • oauth:authorization: element describing SmugMug authorization step (e.g. authorization URL)
  • oauth:param: parameters used to get tokens from json response

The second part of the SmugMug WADL file describes the REST resource with two HTTP GET methods:

  • smugmug_albums_get: get SmugMug photo albums - either for the user specified with NickName parameter or for the user actually logged in
  • smugmug_images_get: get photos for the album specified by AlbumID and AlbumKey

Finally, see the graphical hints how to create a simple SmugMug application in NetBeans IDE:

  1. Register SmugMug WADL:
  2. Create SmuMugClient by using RESTful JavaClient wizard:
  3. Fill in the CONSUMER_KEY and CONSUMER_SECRET to SmugMugClient.java:
        public class SmugMugClient {
    private WebResource webResource;
    private Client client;
    private static final String BASE_URI = "http://api.smugmug.com/services/api/json/1.2.2/";
    private static final String OAUTH_BASE_URL = "http://api.smugmug.com/services/api/json/1.2.2/";
    /**
    * Please, specify the consumer_key string obtained from service API pages
    */
    private static final String CONSUMER_KEY = "1r9ylSm0OQupwresZODqSAeAzYD7VSqa";
    /**
    * Please, specify the consumer_secret string obtained from service API pages
    */
    private static final String CONSUMER_SECRET = "ABCDEFGHb8172709c9d0d8074cfd4d81";
    ...
  4. Write Java client code:
    package smugmugclient;

    import com.sun.jersey.api.client.UniformInterfaceException;
    import java.io.IOException;
    import org.codehaus.jettison.json.JSONArray;
    import org.codehaus.jettison.json.JSONException;
    import org.codehaus.jettison.json.JSONObject;

    /**
    *
    * @author mkuchtiak
    */
    public class Main {

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) throws JSONException {
    SmugMugClient client = new SmugMugClient();
    try {
    client.login();
    client.initOAuth();
    String response = client.smugmug_albums_get(String.class, "NickName=honza");
    JSONObject jsonObject = new JSONObject(response);
    JSONArray albums = (JSONArray)jsonObject.get("Albums");
    System.out.println("");
    for (int i=0; i<albums.length(); i++) {
    JSONObject album = (JSONObject)albums.get(i);
    System.out.println("Album Title: "+album.getString("Title"));
    client.makeOAuthRequestUnique();
    String image = client.smugmug_images_get(String.class, String.valueOf(album.getInt("id")), album.getString("Key"), "Pretty=true", "Extras=ThumbURL,MediumURL,URL");
    System.out.println("Images: "+image);
    System.out.println(".........................................................................");
    }
    } catch (UniformInterfaceException ex) {
    System.out.println("ex = "+ex.getResponse().getEntity(String.class));
    } catch (IOException ex) {
    ex.printStackTrace();
    }
    client.close();
    }

    }
  5. Sample output in JSON format:
    Album Title: London
    Images: {
    "stat": "ok",
    "method": "smugmug.images.get",
    "Album": {
    "id": 3049476,
    "Key": "EecpU",
    "ImageCount": 18,
    "Images": [
    {
    "id": 165994987,
    "Key": "eiCZi",
    "MediumURL": "http://honza.smugmug.com/Travel/London/IMG4114/165994987_eiCZi-M.jpg",
    "ThumbURL": "http://honza.smugmug.com/Travel/London/IMG4114/165994987_eiCZi-Th.jpg",
    "URL": "http://honza.smugmug.com/Travel/London/3049476_EecpU#165994987_eiCZi"
    },
    {
    "id": 165994994,
    "Key": "Dr6pK",
    "MediumURL": "http://honza.smugmug.com/Travel/London/IMG4125/165994994_Dr6pK-M.jpg",
    "ThumbURL": "http://honza.smugmug.com/Travel/London/IMG4125/165994994_Dr6pK-Th.jpg",
    "URL": "http://honza.smugmug.com/Travel/London/3049476_EecpU#165994994_Dr6pK"
    },
    ...
    ],
    "URL": "http://honza.smugmug.com/Travel/London/3049476_EecpU"
    }
    }
    .........................................................................
    Album Title: San Francisco 2007
    Images: {
    "stat": "ok",
    "method": "smugmug.images.get",
    "Album": {
    "id": 2813373,
    "Key": "vtTCV",
    "ImageCount": 14,
    "Images": [
    {
    "id": 150304428,
    "Key": "TfdwZ",
    "MediumURL": "http://honza.smugmug.com/Travel/San-Francisco-2007/IMG2935/150304428_TfdwZ-M.jpg",
    "ThumbURL": "http://honza.smugmug.com/Travel/San-Francisco-2007/IMG2935/150304428_TfdwZ-Th.jpg",
    "URL": "http://honza.smugmug.com/Travel/San-Francisco-2007/2813373_vtTCV#150304428_TfdwZ"
    },
    ...
    ],
    "URL": "http://honza.smugmug.com/Travel/San-Francisco-2007/2813373_vtTCV
  6. And finally, these are authorized requests to SmugMug 1.2.2 API used to get the previous output:

    smugmug.albums.get:
    GET /services/api/json/1.2.2/?method=smugmug.albums.get&NickName=honza HTTP/1.1
    Accept: application/json
    Authorization: OAuth oauth_signature="E4HTtzhMm54hstcKdq06M2hH3mo%3D", oauth_nonce="3f01f695-15a2-4073-be72-81d3826a25fa", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="1r9ylSm0OQupwresZODqSAeAzYD7VSqa", oauth_token="6b8e7829ae6d0f5152fce8e25ab11f94", oauth_timestamp="1275572314"
    User-Agent: Java/1.6.0_17
    Host: api.smugmug.com
    Connection: keep-alive

    smugmug.images.get:
    GET /services/api/json/1.2.2/?AlbumID=3049476&method=smugmug.images.get&AlbumKey=EecpU&Extras=ThumbURL,MediumURL,URL&Pretty=true HTTP/1.1
    Accept: application/json
    Authorization: OAuth oauth_signature="zGagIZG4B%2BIuVqD5Sh1dSjMYXW0%3D", oauth_nonce="e0985dfc-1e21-4c50-9aaf-d59780676355", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="1r9ylSm0OQupwresZODqSAeAzYD7VSqa", oauth_token="6b8e7829ae6d0f5152fce8e25ab11f94", oauth_timestamp="1275572314"
    User-Agent: Java/1.6.0_17
    Host: api.smugmug.com
    Connection: keep-alive
AttachmentSize
register_service.png50.48 KB
smugmugclient.png83.34 KB
0
Your rating: None
Published at DZone with permission of its author, Milan Kuchtiak.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)