Tuesday, June 04, 2013

Google API Fusion Table permissioning

I recently worked on a project where I needed to update an application that leveraged Google Fusion Tables. The Google API changed significantly, and the application did not work anymore. While I found a good Fusion Table coding example of how to get the Java code changed properly, I had a lot of difficulty getting the permissioning set up.

Here is a brief summary of how I got it to work, in the hopes that it might help others who are having similar problems:

Connect the table to the Fusion Table application

  • If the table you are interested in is not already connected to Fusion Tables, click it in your Google Drive, and then click the Connect button.

Turn on the Fusion Table API Service

  • Open the Google API Console
  • Create a new project if you need to
  • In Services, turn on Fusion Tables API

Set up a Service Account

  • In the Google API Console, open API Access and click the Create an OAuth 2.0 client ID button
  • Enter a Product Name and click Next
  • Click the Service Account radio button, and then Create Client ID
  • Download the key file into your project, and rename it to whatever is appropriate for you to use in your application
  • You will also need the "Email Address", which is referred to as the "Application ID" within the API

Set permissions on the table file

This one was really difficult to figure out. If you need to do INSERTs or DELETEs into the Fusion Table, then you will need to set "writer" permissions for the Service Account. If you only need to SELECT from your application, then you can skip this step, of course.

  • Open the Google Drive SDK Permissions Page
  • Turn on the Authorize requests using OAuth 2.0 toggle (you should be prompted to authorize)
  • Enter the following information:
    • Field: [the fusion table ID]
    • role: writer
    • type: user
    • value: ["Email Address" from the Console]

Java code

That should be it. Following the example code, you will set up a credential:

credential = new GoogleCredential.Builder()
   
.setTransport(HTTP_TRANSPORT)
   
.setJsonFactory(JSON_FACTORY)
   
.setServiceAccountId(config.getAccountId())
   
.setServiceAccountScopes(Collections.singleton(FusiontablesScopes.FUSIONTABLES))
   
.setServiceAccountPrivateKeyFromP12File(keyFile)
   
.build();

Make your Fusion Table object:

fusiontables = new Fusiontables.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).build();

Run your various SQL statements:

response = fusiontables.query().sql(insertSql).execute();

Hope that helps someone!

Saturday, May 11, 2013

BigDecimal.equals() vs. compareTo() Performance Test


Problem


There is much debate online about the merits of using the BigDecimal.equals(Object) method. In the equals method, scale is considered in such a way that 1.0 != 1.00. The compareTo method, however, ignores scale, meaning that 1.0 == 1.00. In this specific case, however, scale is known, so either method will work. Out of curiosity, I wondered if there was a performance hit in either method.

Approach

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.security.SecureRandom;

import org.joda.time.DateTime;
import org.junit.Test;

/**
 <p>
 * Class to test the performance of {@link BigDecimal#equals(Object)} vs.
 {@link BigDecimal#compareTo(BigDecimal)}. The question at hand is which
 * method to use when the precision and scale of the BigDecimals being compared
 * is know to be the same.
 </p>
 <p>
 * In the equals method, scale is considered in such a way that 1.0 != 1.00. The
 * compareTo method, however, ignores scale, meaning that 1.0 == 1.00. In this
 * specific case, however, scale is known, so either method will work. Out of
 * curiosity, I wondered if there was a performance hit in either method.
 </p>
 */
public class BigDecimalPerformanceTest {

    /** The {@link SecureRandom} object. */
    public static final SecureRandom RANDOM = new SecureRandom();

    /** The number of times to loop over each comparison. */
    public static final int ITERATIONS = 100000000;

    /** The number of times to loop over all comparisons. */
    public static final int LOOPS = 3;

    /** BigDecimal precision. */
    private static final int PRECISION = 15;

    /** BigDecimal scale. */
    private static final int SCALE = 2;

    /** Equals vs. compareTo. */
    @SuppressWarnings("unused")
    @Test
    public void equalsVsCompareTo() {
        for (int j = 0; j < LOOPS; j++) {
            /* Reference object to do all the comparisons against. */
            BigDecimal testBigDecimal = makeBigDecimal();

            /*
             * Classic equals method. Assigning results to a variable for
             * consistency.
             */
            DateTime startTime = new DateTime();
            for (int i = 0; i < ITERATIONS; i++) {
                boolean test = testBigDecimal.equals(makeBigDecimal());
            }
            DateTime endTime = new DateTime();
            System.out.println("BigDecimal.equals()    : "
                               + endTime.minus(startTime.getMillis()).toString("m:s.SSS"));

            /* Plain compareTo method. */
            startTime = new DateTime();
            for (int i = 0; i < ITERATIONS; i++) {
                int test = testBigDecimal.compareTo(makeBigDecimal());
            }
            endTime = new DateTime();
            System.out.println("BigDecimal.compareTo()1: "
                               + endTime.minus(startTime.getMillis()).toString("m:s.SSS"));

            /*
             * Convert compareTo to true/false as a closer comparison with
             * equals as far as actual usage would be concerned.
             */
            startTime = new DateTime();
            for (int i = 0; i < ITERATIONS; i++) {
                boolean test = testBigDecimal.compareTo(makeBigDecimal()) == 0;
            }
            endTime = new DateTime();
            System.out.println("BigDecimal.compareTo()2: "
                               + endTime.minus(startTime.getMillis()).toString("m:s.SSS"));
        }
    }

    /**
     * Make big decimal.
     
     @return the big decimal
     */
    private BigDecimal makeBigDecimal() {
        return new BigDecimal(RANDOM.nextDouble()new MathContext(PRECISION, RoundingMode.HALF_UP))
                .setScale(SCALE, RoundingMode.HALF_UP);
    }
}

Output


BigDecimal.equals()    : 3:42.909
BigDecimal.compareTo()1: 3:44.995
BigDecimal.compareTo()2: 3:49.476
BigDecimal.equals()    : 3:48.313
BigDecimal.compareTo()1: 3:42.152
BigDecimal.compareTo()2: 3:43.889
BigDecimal.equals()    : 3:42.079
BigDecimal.compareTo()1: 3:44.639
BigDecimal.compareTo()2: 3:42.564

Conclusion


When you know the scale of a BigDecimal will be consistent, equals() and compareTo() perform equally as well. In my case, I chose to stick with using equals(), as it is immediately obvious in the code what I am trying to accomplish.