DDi Compendium API and Java Classes?

Progress reports and musings from the developers on the current gaming tools.

Moderators: dorpond, trevor, Azhrei

User avatar
Blakey
Dragon
Posts: 778
Joined: Fri Mar 23, 2007 11:27 am
Location: Sussex, UK.

Re: DDi Compendium API and Java Classes?

Post by Blakey »

My successful class to implement a CompendiumEntry. It's not pretty and needs cleaning up in places but it works!

Code: Select all

package info.rodinia.tokenmaker;

import java.io.*;
import java.net.*;
import java.util.*;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;

// a simple class which models a compendium entry
public class CompendiumEntry {

    private String myHTMLSource;
    private String myURL;
    private String actionUrl;
    private static final String baseURL = "http://www.wizards.com/dndinsider/compendium/";
    private String email;
    private String password;
    private NameValuePair[] myPostData = null;

    // constructor takes a URL and builds an entry from it.
    public CompendiumEntry(String stringUrl) {
	myURL = stringUrl;
	init();
    }

    private void init() {
	try {
	    HttpClient client = new HttpClient();
	    GetMethod get = new GetMethod(myURL);
	    client.executeMethod(get);
	    myHTMLSource = get.getResponseBodyAsString();
	    get.releaseConnection();

	    // figure out where we have to go to post the response - look up
	    // the 'action=' tag
	    parseAction(myHTMLSource);
	    // if our actionUrl contains login.aspx
	    // then we need to login - so post the data back to the form
	    if (actionUrl.contains("login.aspx")) {
		if (myPostData == null) {
		    // go and read DDi login details from file
		    readLoginDetails("tokenmaker.dat");

		    // Now go and set up the post data
		    myPostData = new NameValuePair[5];
		    myPostData[0] = new NameValuePair("email", email);
		    myPostData[1] = new NameValuePair("password", password);
		    // do the other fields in postData
		    parseFormData(myHTMLSource);
		}

		// POST back with login details included.
		PostMethod post = new PostMethod(actionUrl);
		post.setRequestBody(myPostData);
		client.executeMethod(post);
		post.releaseConnection();
		// we're now logged in so just read the URL
		get = new GetMethod(myURL);
		client.executeMethod(get);
		myHTMLSource = get.getResponseBodyAsString();
		get.releaseConnection();
	    }
	    formatHTML();
	    System.out.println(myHTMLSource);

	} catch (Exception e) {
	    System.err.println("Error initializing a CompendiumEntry: " + e);
	}
    }

    // take myHTMLSource and add in the formatting strings to pick up formating
    // from wizards
    private void formatHTML() {
	myHTMLSource = myHTMLSource.replace("href=\"",
		"href=\"http://www.wizards.com/dndinsider/compendium/");
	myHTMLSource = myHTMLSource.replace("<h1 ", "<h1 style=\"color:white\" ");
    }

    // give back the source
    public String getHTML() {
	return myHTMLSource;
    }

    public String getURL() {
	return myURL;
    }

    // Go get the users DDi account info from a file.
    private void readLoginDetails(String filename) {
	try {
	    File file = new File(filename);
	    FileReader r = new FileReader(file);
	    BufferedReader reader = new BufferedReader(r);
	    email = reader.readLine();
	    password = reader.readLine();
	    reader.close();

	} catch (Exception e) {
	    System.err.println("Error opening login details file: " + e);
	}

    }

    // Take a string which contains the source of an HTML file and parse it for
    // the <input> tags that need to be used to perform a POST on a page.
    private void parseFormData(String source) {
	try {

	    int i = 2; // index into myPostData;
	    while (source.contains("<input")) {

		// First grep out the <input> tag.
		int start = source.indexOf("<input");
		String input = source.substring(start);
		int end = input.indexOf('>');
		input = input.substring(0, end + 1);
		source = source.substring(start + end);

		// Now grep the type= attribute from the input tag
		if ((start = input.indexOf("type=")) != -1) {
		    String type = input.substring(start + 6);
		    end = type.indexOf("\"");
		    type = type.substring(0, end);
		    if (type.equals("text") || type.equals("password"))
			continue; // we can't deal with text fields here.
		}

		// Now grep the name= attribute from the input tag
		start = input.indexOf("name=");
		String name = input.substring(start + 6);
		end = name.indexOf("\"");
		name = name.substring(0, end);
		// System.out.println("Name: " +name);

		// Now grep the value= attribute from the input tag
		start = input.indexOf("value=");
		String value = input.substring(start + 7);
		end = value.indexOf("\"");
		value = value.substring(0, end);
		// System.out.println("Value: " +value);
		myPostData[i++] = new NameValuePair(name, value);
	    }
	} catch (Exception e) {
	    System.err
		    .println("Error parsing login source for form data: " + e);
	}
    }

    // Take a string which contains the source of an HTML file and parse it for
    // the action="file" tag.
    private void parseAction(String source) {
	int start = source.indexOf("action=");
	String action = source.substring(start + 8);
	int end = action.indexOf("\"");
	actionUrl = baseURL + action.substring(0, end);
    }
}

The guy in the green hat.

User avatar
Hawke
Great Wyrm
Posts: 2261
Joined: Sat Apr 21, 2007 12:12 am
Location: Albuquerque, NM

Re: DDi Compendium API and Java Classes?

Post by Hawke »

Super promising! Can't wait to see it in action sometime =)

User avatar
Blakey
Dragon
Posts: 778
Joined: Fri Mar 23, 2007 11:27 am
Location: Sussex, UK.

Re: DDi Compendium API and Java Classes?

Post by Blakey »

Hawke wrote:Super promising! Can't wait to see it in action sometime =)
Some screen grabs of what I have so far are here.
The guy in the green hat.

ryatziv
Kobold
Posts: 1
Joined: Sun Mar 13, 2011 8:01 pm

Re: DDi Compendium API and Java Classes?

Post by ryatziv »

I'm trying to adapt your code into my application, but I'm getting stuck at the "2-cookie-back-to-login" stage. Can you help me? parseAction() and parseFormData() are nearly identical to yours, except for they return the correct datatype for this code.

Code: Select all

try {
                HttpClient client = new DefaultHttpClient();
                client.execute(new HttpGet("http://www.wizards.com/favicon.ico"));
                HttpGet get = new HttpGet(selection.getLink());
            
                HttpResponse response = client.execute(get);
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    long len = entity.getContentLength();
                    String myHTMLSource = EntityUtils
                    .toString(entity);
                    String urlForPost = parseAction(myHTMLSource);
                    List<NameValuePair> params = parseFormData(myHTMLSource);
                    get.abort();
                    
                    params.add(new BasicNameValuePair("email", "[email protected]"));
                    params.add(new BasicNameValuePair("password", "pass"));
                    
                    UrlEncodedFormEntity urlentity = new UrlEncodedFormEntity(params, "UTF-16");
                    HttpPost post = new HttpPost(urlForPost);
                    post.setEntity(urlentity);
                    client.execute(post);
                    post.abort();

                    get = new HttpGet(selection.getLink());
                    response = client.execute(get);
                    entity = response.getEntity();
                    if (entity != null) {
                        len = entity.getContentLength();
                        System.out.println(EntityUtils.toString(entity));
                        get.abort();
                    }
                }
            }
            catch (ClientProtocolException e) {
                e.printStackTrace();
            }
            catch (IOException e) {
                e.printStackTrace();
            }

Post Reply

Return to “Developer Notes”