Escaping JSON in FreeMaker

The ?js_string doesn’t work quite right for JSON since it ends up escaping single-quotes. This isn’t quite right for JSON since it only allows Strings to be specified using double-quotes. Therefore, in order to properly escape Strings in FreeMarker for JSON, you need to write a custom method and add it to the model. Here’s my code for a JSON escaper method:

public class JSONEscape implements TemplateMethodModelEx {
  @Override
  public Object exec(List arguments) throws TemplateModelException {
    if (arguments.size() != 1) {
      throw new TemplateModelException("jsonescape takes a single parameter");
    }

    return JSONBuilder.escape(arguments.get(0).toString());
  }
}

The JSONBuilder is a class that I wrote for creating JSON using the builder pattern. However, the escape method looks like this:

  public static String escape(String str) {
    StringBuilder build = new StringBuilder();
    escape(str, build);
    return build.toString();
  }

  public static void escape(String str, StringBuilder build) {
    char[] ca = str.toCharArray();
    for (char c : ca) {
      switch (c) {
        case '"':
        case '\\':
          build.append('\\');
          build.append(c);
          break;
        case '\r':
          build.append("\\r");
          break;
        case '\n':
          build.append("\\n");
          break;
        case '\t':
          build.append("\\t");
          break;
        case '\b':
          build.append("\\b");
          break;
        case '\f':
          build.append("\\f");
          break;
        case '/':
          build.append("\\/");
          break;
        default:
          if (c < = 0x1F) {
            unicodeEscape(c, build);
          } else {
            build.append(c);
          }
      }
    }
  }

  public static void unicodeEscape(int ch, StringBuilder build) {
    build.append('\\');
    build.append('u');
    build.append(HEX_CHARS[ch >>> 12]);
    build.append(HEX_CHARS[(ch >>> 8) & 0xf]);
    build.append(HEX_CHARS[(ch >>> 4) & 0xf]);
    build.append(HEX_CHARS[ch & 0xf]);
  }

Then I add this method to my model and render the template:

model.put("jsonescape", new JSONEscape());

My templates look like this:

{
  "foo": "${jsonescape(some.value.here)}"
}
Posted in FreeMaker, Java, WebService | 1 Comment

Friendster can’t even send email

I’m surprised that Friendster is even still around, but today I got an email from their CEO and it had the entire MIME body in the message. These guys can’t even figure out how to send email.

X-Campaign-ID: 8002
X-Campaign-Type: 1
X-Message-Ref: 19lGRwmaJkSjEf8FZP7XSCijJOJhOejGu832ySW13bA*
Content-Type: multipart/alternative; boundary="----_=_FSter_001_3251309519900466"
MIME-Version: 1.0

This is a MIME email, the first part is the text message.

------_=_FSter_001_3251309519900466
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

Friendster www.friendster.com July 2011

A Personal Message from Friendster's CEO

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Dear fellow Friendster members,
As many of you may know, Friendster announced that it is re-launching itself as a social gaming portal and launched a beta version of the new Friendster a couple of weeks ago. The beta version was well received. I am pleased to announce that the new Friendster is going live thereby enabling all our users to login to the new Friendster using your existing Friendster username and password.
Friendster has touched the lives of many. Since MOL, the company I founded acquired Friendster in early last year; many people have come up to me to tell me how Friendster has changed their lives. Many have told me that they have found their life partners over Friendster. Just last week, a successful Internet entrepreneur in Singapore told me that her success was triggered by promoting her business on Friendster. Friendster pioneered social networking and ignited the social media industry that has created billion dollar companies such as Facebook and Twitter, companies that may not have existed in their present form if not for Friendster's early innovation.
Today, Friendster is in a unique position to take advantage on the growth of social gaming. Through its relationship with MOL, which has a 10 year history in working with gaming companies, Friendster has both the experience and track record to make innovations in this space.
Today, as Friendster reinvents itself as a social gaming destination that enables its users to create multiple avatars, play games and enjoy rewards; I hope that all of you will wish us luck and continue to support us in our new reincarnation. The new Friendster is not perfect and we will continue to add new games and features such as localization and rewards over the next few months. Our team is working hard on adding these features and welcomes your suggestions and comments on how we can better serve your needs as a social gaming and entertainment destination.
I would like to take this opportunity to thank all of you for your support and hope that all of you will enjoy the new Friendster as Friendster continues to innovate to serve and entertain you better.
Yours truly,
Ganesh Kumar Bangah
Chief Executive Officer
ceo@friendster.com

****************************************************************
To manage your notification preferences go to: http://www.friendster.com/account/notifications
Copyright 2002-2011 Friendster, Inc. All rights reserved.
****************************************************************

------_=_FSter_001_3251309519900466
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: 7bit

[SNIP - I cut out the HTML so I didn't have to escape everything by hand]

------_=_FSter_001_3251309519900466--

Posted in Engineering, Misc | 4 Comments

JDBC Batch vs. Multi-Row Inserts

I recently had a requirement to insert a few hudred rows into a relational database ever couple of seconds. Generally this could be accomplished during the request, but I didn’t want to introduce issues if there were spikes. Therefore, I figured I would cache the data and then write it out in a background thread every few seconds. This would also increase my response time during requests.

I wasn’t sure whether or not JDBC batch or using a single insert statement that inserted multiple rows would be faster. Therefore, I setup a little test to see which was going to work better. First some code:

Here is the code for a single insert statement that inserts multiple rows.

long start = System.currentTimeMillis();
StringBuilder build = new StringBuilder("insert into insert_values (foo, bar, baz) values ");
for (int i = 0; i < 1000; i++) {
  build.append("(?, ?, ?)");
  if (i < 999) {
    build.append(", ");
  } else {
    build.append(";");
  }
}

Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/batch_vs_insert_test", "dev", "dev");
c.setAutoCommit(false);
PreparedStatement ps = c.prepareStatement(build.toString());
for (int i = 0; i < 3000; i++) {
  ps.setString(i + 1, "value" + i);
}

int result = ps.executeUpdate();
c.commit();

long end = System.currentTimeMillis();
System.out.println("Insert time was " + (end - start));

ps.close();
c.close();

Here is the code for the JDBC batch:

long start = System.currentTimeMillis();
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/batch_vs_insert_test", "dev", "dev");
c.setAutoCommit(false);
PreparedStatement ps = c.prepareStatement("insert into insert_values (foo, bar, baz) values (?, ?, ?);");
for (int i = 0; i < 3000; i++) {
  ps.setString((i % 3) + 1, "value" + i);
  if ((i + 1) % 3 == 0) {
    ps.addBatch();
  }
}

int[] results = ps.executeBatch();
c.commit();

long end = System.currentTimeMillis();
System.out.println("Batch time was " + (end - start));

ps.close();
c.close();

The average time over 10 iterations where roughly as follows:

JDBC Batch: ~100 milliseconds
Single Insert: ~10 milliseconds

It looks like the single insert statement wins by a large margin.

Posted in Java | Leave a comment

iMac vs. build-your-own

I’ve been meaning to do this comparison for a while now, but this morning I decided to just jump in and do it. A lot of people are constantly complaining about how expensive Macs are and I’ve long held the notion that they are quite reasonably priced.

Here’s my break down:

  • CPU (i7 2600K 3.4GHz Sandybridge) $320
  • Motherboard (ASUS P8P67) $185
  • RAM (8GB DDR3 1333MHz) $83
  • Hard Drive (WD 1TB 7,200 RPM SATA 6G) $85
  • Video (ATI Radeon 6970M) $300
  • Keyboard/Mouse (MS wireless) $80
  • Monitor (Dell Ultrasharp 27″ 2560×1440) $1000
  • Webcam (Any) $50
  • Speakers (Any) $15

The main expense here is definitely the CPU and the monitor. However, for equal comparisons I wanted to add a monitor that was comparable in quality, display, depth, etc. You could obviously go with a cheaper monitor from an off-brand, but I think that’s not a fair comparison.

Here’s the results:

  • Apple iMac 27″ with 3.4 GHz CPU and 8GB RAM factory installed: $2,199
  • BYO with above specs: $2,118

The difference is about $81.

I poked around a bit at some desktop solutions as well, and even an entry level desktop with the i7 2600K and the Dell ultrasharp monitor is going to start around $2,000.

It looks like my notion about the value of a Mac is accurate. Furthermore, with the fact that the iMac is a single piece of equipment that includes the computer and the monitor and you get what I still feel is the worlds best operating system plus a bunch of free software, it is hard to argue that an iMac isn’t a great value.

Posted in Java | Leave a comment

Java Road Trip – Where have all our heroes gone?

I got an email from Oracle about the Java Road Trip. Looking over the website I wasn’t immediately excited to attend the event here in Denver. But even more than that, I looked at the profiles for the speakers and the staff and all I can say is, “Where have all our heroes gone?”

I didn’t recognize a single name. Maybe I just don’t get out much anymore. Or maybe Sun did a piss poor job of promoting their employees and rock-stars. Or maybe they shackled them to their desks or something. Who knows?

Hopefully Oracle and fix some of that and help me recognize the name “Tony Printezis” and be excited that he’s working on the JVM.

Posted in Java | Leave a comment