Leveraging Google App Engine Mail and XMPP Services with CFML

In my previous few posts on Open BlueDragon for Google App Engine (GAE) I’ve done a basic introduction to GAE, discussed the Google Datastore, and dug into how to use the virtual file system and the GAE Image Service to handle file uploads and simple image processing.

In this post we’ll pick back up with my sample app (.tar.gz, 15.3 MB) from OpenCF Summit 2011 and look into two more of the excellent services available to you on GAE, specifically the mail and XMPP services.

Mail? So What?

Sending email is of course a big yawn–anyone can do that from any platform quite easily. But what if you want your application to be able to receive mail and take actions based on the mail it receives?

The standard solution is typically to set up a dummy email address (myapp@foo.com) and then have your application poll the mailbox for new mail, which in the case of a CFML app means setting up a scheduled task to do a CFPOP call to the mailbox in question. You then get back a list of messages and have to handle them as needed for your application.

This works, but it’s a pretty passive, braindead approach to solving the problem, and you wind up having to write a bunch of code to manage a mailbox designed for humans that’s being used by your application.

With GAE you can have your application respond to incoming email directly without having to set up any mailboxes, because the ability for your app to receive mail is built right into the GAE platform. You simply enable mail services in your appengine-web.xml file, configure specific email addresses or wildcard email addresses in web.xml, and your application can receive mail.

Configuring Inbound Services

Let’s take a look at appengine-web.xml, which if you’re following along with the sample app is in the war/WEB-INF directory. Towards the bottom of the file you’ll see a block of inbound services defined:


<inbound-services>
    <service>xmpp_message</service>
    <service>xmpp_presence</service>
    <service>xmpp_subscribe</service>
    <service>mail</service>
</inbound-services>

Note that by default there are no inbound services enabled on your GAE application, so you do have to specify these. We’ll be covering the XMPP services in this post as well, so you can see in the block above this is where specific granular XMPP services such as messaging, presence, and subscription are enabled.

That’s it! With that simple block in appengine-web.xml when you deploy your application to GAE, it will be ready to receive email and interact with XMPP messages.

At this point you’re probably wondering basic things like the address to which you can send email, how to handle the email once it’s received, how to configure specific email addresses, and a host of other things, so let’s dig in a bit more.

How the Magic Works

Once you have mail defined as an inbound service, your application essentially gets a mail server on the internet at the address YOUR_APP_ID.appspotmail.com. So with mail in the inbound services block in your config file, once you fire up your app on GAE mail can be sent to ANY_ADDRESS@YOUR_APP_ID.appspotmail.com. We’ll talk more about how the ANY_ADDRESS bit works in a minute when we look at writing code to handle incoming mail.

Google very cleverly designed many of their services to send messages to your application via an HTTP POST to a specific URL. In the case of inbound mail, any mail sent to ANY_ADDRESS@YOUR_APP_ID.appspotmail.com generates an HTTP POST to the URL /_ah/mail/{EMAIL_ADDRESS} with email address representing the full email address including the YOUR_APP_ID.appspotmail.com domain.

Since there’s a lot of magic behind the scenes that you don’t have to configure, let’s review how this works before moving on to the code for handling incoming mail.

  1. You enable mail as an inbound service in appengine-web.xml
  2. When deployed to GAE, your app can then receive email at ANY_ADDRESS@YOUR_APP_ID.appspotmail.com
  3. When mail is received at YOUR_APP_ID.appspotmail.com, this generates an HTTP POST to the url /_ah/mail/{EMAIL_ADDRESS} within your application

Now let’s look at how to write code to process incoming mail.

Processing Inbound Mail

With very little effort on our part our application can receive mail. That’s cool in theory, but how do we write code to react to this inbound mail?

Since all mail comes in as an HTTP POST, the way you handle inbound mail is more or less the same way you’d handle any POST request to your application. This makes handling all of this very simple since handling POST requests is something with which we’re all too familiar.

From a CFML standpoint there’s a bit of a disconnect here since, at least until I figure out a clever hack, the thing that receives the mail has to be a Java servlet. Not to worry, the code’s quite straight-forward and we can hand off any real work we want to do to CFML once we get the mail in the servlet.

Bit of a detour to explain why (at this point) CFML can’t handle the inbound mail directly. In order for your application to take action when mail is received, you have to define a servlet mapping for the special incoming mail URL of /_ah/mail/{EMAIL_ADDRESS}. Servlet mappings do support wildcards, so for the sample application I’ve defined a servlet mapping of /_ah/mail/* that will route all inbound mail, regardless of the specific email address, to the same servlet.

You could of course define specific servlet mappings for specific addresses, e.g. one servlet mapping for /_ah/mail/user1@yourappid.appspotmail.com and another for /_ah/mail/user2@yourappid.appspotmail.com if you needed two completely separate servlets to handle the different users. I hinted at this above, but I’ll point out here again that you do not need to configure mailboxes or anything along those lines for specific users. Your application will receive absolutely any mail sent to ANYONE@yourappid.appspotmail.com and how you handle the ANYONE part is up to you to define in your code.

Back to the CFML discussion. When I was first messing with the in the local GAE environment, I first thought I’d be clever and just define a real directory path in my application of /_ah/mail, throw an index.cfm file in there to act as a controller, and I’d be off to the races. That actually kind of worked locally, but the issue is when you deploy to GAE it won’t let you deploy your application if you have /_ah as a real directory since that’s a reserved directory for things like the admin console.

With that door shut, I next figured I could define the servlet mapping for /_ah/mail/* to point to the CFML servlet like so:


<servlet-mapping>
    <servlet-name>cfmServlet</servlet-name>
    <url-pattern>/_ah/mail/*</url-pattern>
</servlet-mapping>

This kind of worked as well, meaning I could at least see it was hitting the CFML servlet since I could dump things in Application.cfc and see what was going on. The issue here turned out to be that I coudln’t really leverage anything like onRequestStart in Application.cfc and take any action there, because when a POST comes in to /_ah/mail/* there’s no page argument, which is what onRequestStart expects.

I’m convinced there’s a way to get this to work (or I’m at least convinced I haven’t yet exhausted all avenues of failure here), but since I was under a time crunch to get this rolling for OpenCF Summit, I decided to write a simple servlet to handle inbound mail and then hand things off to CFML for some additional work. I haven’t had time yet to revisit this so if anyone has any ideas based on what I’m describing of how we could get mail to hit CFML directly I’d be very interested to hear them.

The MailReceiverServlet

In the sample app project the code for the MailReceiverServlet is in the src directory, and then in the package org.opencfsummit. As I mentioned above it’s pretty straight-forward, but let’s go over the mail specific parts since this will help shed some light on how mail comes in via the POST to /_ah/mail.

Inside the servlet’s doPost method we first declare some variables and set some defaults starting on line 23:


Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage message;
Address[] toAddresses = null;
Address[] fromAddresses = null;
ArrayList<String> recipients = null;
ArrayList<String> senders = null;

Couple of things to note here. First, just so there’s no confusion the Session in this case is a javax.mail.Session, not an HttpSession. So you can see here we’re dealing with actual Java mail stuff when the POST hits our servlet, which is also evidenced by the MimeMessage and javax.mail.Address arrays. The two string ArrayLists at the end we’ll use in a minute as an easy way to pass off the data we want to be available in CFML.

Next up in MailReceiverServlet we get the data from the inbound mail and parse out the to and from addresses:


try {
    message = new MimeMessage(session, request.getInputStream());

    toAddresses = message.getAllRecipients();
    recipients = new ArrayList<String>();

    fromAddresses = message.getFrom();
    senders = new ArrayList<String>();

    for (Address address : toAddresses) {
        recipients.add(address.toString());
    }

    for (Address address : fromAddresses) {
        senders.add(address.toString());
    }
} catch (MessagingException me) {
    // gulp
}

Let’s step through that code briefly.

First, we instantiate a new MimeMessage using a mail session and the data coming from the request’s input stream. Once we have a handle on the message, we can get all of the to addresses contained in the message (message.getAllRecipients()) and all the from addresses as well (message.getFrom()).

We then loop over each address array (toAddresses and fromAddresses) and add each address as a String to the ArrayLists (recipients and senders).

With the simple string versions of the addresses in ArrayLists, we’ll then set these as attributes in the request object and forward the request to a CFML page:


request.setAttribute("senders", senders);
request.setAttribute("recipients", receipients);
getServletContext().getRequestDispatcher("/mailhandler.cfm").forward(request, response);

What this last chunk of code does it puts the senders and recipients ArrayLists in the request object, which translates into the request scope on the CFML side, and then forwards the request to mailhandler.cfm for some additional work.

And of course we have to define this servlet and a servlet mapping in our web.xml:


<servlet>
    <servlet-name>mailReceiver</servlet-name>
    <servlet-class>org.opencfsummit.MailReceiverServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>mailReceiver</servlet-name>
    <url-pattern>/_ah/mail/*
</servlet-mapping>

mailhandler.cfm

With the initial incoming mail request handled by our MailReceiverServlet and the request forwarded to mailhandler.cfm (which is in the war directory if you’re following along in the sample app), we can make quick work of the rest of our task.

This might not be the most practical example, but for the purposes of demonstration what we’re doing in mailhandler.cfm is if anyone sends an email to stallmanbook@opencfsummit2011.appspotmail.com the application will respond by emailing a copy of Richard Stallman’s Free Software, Free Society as a PDF attachment. Of course you can do anything you want when your app receives an email but this is the little sample I dreamed up. And this is live by the way, so go ahead and try sending an email to stallmanbook@opencfsummit2011.appspotmail.com to get your free gift. 😉

In mailhandler.cfm we first check to see if the recipients array (which is the ArrayList of strings that we created in MailReceiverServlet and then put in the request object) contains the appropriate email address for this particular action:


<cfif request.recipients.contains("stallmanbook@opencfsummit2011.appspotmail.com")>

Remember that when we configured the servlet mapping for MailReceiverServlet we used a wildcard in the URL pattern (/_ah/mail/*), so all inbound mail to any address will hit MailReceiverServlet. We only want to our app to send a copy of Stallman’s book when one of the “to” addresses on the inbound email is stallmanbook@opencfsummit2011.appspotmail.com

After we check to see if the correct email address is one of the “to” addresses, we loop over the “from” addresses and use our old friend CFMAIL to send an email with the PDF attachment to each “from” address:


<cfloop index="i" from="1" to="#ArrayLen(request.senders)#">
    <cfmail from="stallmanbook@opencfsummit2011.appspotmail.com"
                to="#request.senders[i]#"
                subject="Stallman Book!"
                mimeattach="#ExpandPath('/pdfs/fsfs-ii-2.pdf')#">
Here is the Stallman book you asked for. Enjoy!
    </cfmail>
</cfloop>

Pretty slick, huh?

Now that we’re well-versed in receiving mail, let’s move on to XMPP. Luckily since many of the basic concepts are the same we’ll be able to pick up the pace a bit.

Google App Engine XMPP Service

The GAE XMPP service works very similarly to the mail service, with a few more options specific to XMPP. If you’re not familiar with XMPP, XMPP stands for “Extensible Messaging and Presence Protocol” and while it can be used in a variety of ways, the usage people are most familiar with is for instant messaging. If you use Google Talk, you use XMPP. Also you may be running something like your own Jabber or OpenFire server in your organizaion for non-public IM, and these are based on XMPP.

As a quick reminder, when we configured inbound services for XMPP on our app we enabled:

  • xmpp_message: allows the app to receive XMPP messages
  • xmpp_presence: allows other XMPP users to see your applicaton’s IM user presence (online, offline, busy, etc.)
  • xmpp_subscribe: allows other XMPP users to “friend” your application’s IM user as well as exchange message and status data

As with inbound mail, in order to get this running on your app all you need to do is specify XMPP inbound services in appengine-web.xml. With that in place once you deploy your app it is XMPP enabled.

Also as with inbound mail, your application gets its own XMPP IDs automatically. So once you enable XMPP your application can interact with the XMPP world using one of these two ID formats:

(And yes, the domain is different between these two ID formats. The first is appspot.com, the second is appspotchat.com.)

Yet again as with inbound mail (I hope you’re sensing a pattern), when an XMPP message hits your application it generates an HTTP POST to /_ah/xmpp/message/chat so all you have to do is write whatever code you want to handle incoming XMPP messages.

The XmppReceiverServlet

As discussed above it isn’t really possible (yet) to have a POST to /_ah/xmpp/message/chat hit CFML directly, so we need a servlet that will handle POSTS to this URL pattern. The code for XmppReceiverServlet in the sample app projects is in the src directory, in the org.opencfsummit package.

First we declare some static final service type stuff in our servlet starting on line 21:


private static final Logger log = Logger.getLogger(XmppReceiverServlet.class.getName());
private static final XMPPService xmppService = XMPPServiceFactory.getXMPPService();

This gives us a logger so we can log incoming messages, as well as the service we’ll be using to parse the inbound XMPP message. Side note: logging on GAE is a bit quirky so make sure and check my post about configuring logging on GAE if you run into issues.

In the doPost method in XmppReceiverServlet we’ll parse the message, do some logging, parrot the message back to the sender (just to show we can send XMPP), and then we’ll again forward the request on to a CFML page to do some additional stuff.


Message message = xmppService.parseMessage(request);
JID jid = message.getFromJid();
String body = message.getBody();
log.info(jid.getId() + " --> opencfsummit2011: " + body);

message = new MessageBuilder().withRecipientJids(jid).withBody(body).build();
xmppService.sendMessage(message);

request.setAttribute("toJID", "opencfsummit2011@appspot.com");
request.setAttribute("fromJID", jid.getId());
request.setAttribute("messageType", message.getMessageType().toString());
request.setAttribute("body", body);

getServletContext().getRequestDispatcher("/xmppdump.cfm").forward(request, response);

That’s a bit of a mouthful so let’s walk through this.

First we use the xmppService to parse the XMPP message out of the request object. This gives us an object of type com.google.appengine.api.xmpp.Message and represents the incoming XMPP message. Next, we get the user ID (JID) of the XMPP user who sent the message as an object of type com.google.appengine.api.xmpp.JID, and get the body of the message as a string. We then log this info which I was simply using for debugging purposes as I was working on the sample app.

Next, we build a new XMPP message using the MessageBuilder, and use the xmppService to send the user’s message back to them. Obviously this isn’t a great real-world example but getting the message you send bounced back to you is a nice way to make sure things are working properly.

After that, we put all the relevant information from the XMPP message into the request object so we’ll have it available in the request scope on the CFML side. We then forward the request to xmppdump.cfm.

As with any servlet we need to add this to our web.xml and set up a servlet mapping so this servlet will respond to POSTs to /_ah/xmpp/message/chat:


<servlet>
    <servlet-name>xmppReceiver</servlet-name>
    <servlet-class>org.opencfsummit.XmppReceiverServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>xmppReceiver</servlet-name>
    <url-pattern>/_ah/xmpp/message/chat/</url-pattern>
</servlet-mapping>

xmppdump.cfm

Once the request is forwarded to xmppdump.cfm (which is in the war directory of the project) we can do anything we want with this information on the CFML side. In this case I’m first emailing myself the contents of CFDUMP for debugging/testing purposes:


<cfsavecontent variable="foo">
    <cfdump />
</cfsavecontent>

<cfmail from="mpwoodward@gmail.com"
            to="matt@mattwoodward.com"
            subject="foo" type="html">
#foo#
</cfmail>

One thing I didn’t mention earlier about sending mail from your GAE app is that the from address must be either:

  • An administrator/developer on the application, or
  • The address of the user who’s currently signed in with their Google Account, or
  • A valid “receiving” email address for the application (e.g. whatever@myappid.appspotmail.com)

Next, I decided just for fun I’d leverage CFHTTP to create a bit of an XMPP-to-SMS service. Any IMs that come into the application are turned into an SMS and sent to a (in this case hard-coded) mobile number using Twilio.


<cfhttp result="smsTestSend"
        method="post"
        url="https://MY_TWILIO_URL"
        username="bar"
        password="baz">
    <cfhttpparam type="formfield" name="From" value="5551234567" />
    <cfhttpparam type="formfield" name="To" value="5559876543" />
    <cfhttpparam type="formfield" name="Body" value="#request.body#" />
</cfhttp>

As you can see Twilio just takes an HTTP POST and turns it into an SMS message, and here since I have the body of the inbound XMPP message available as request.body, that’s what becomes the body of the SMS message.

Yet another example that’s of dubious use in the real world, but I hope it illustrates the points.

Try It Out!

This sample is live as well. I removed the part that sends text messages but you can log into Google Talk and add opencfsummit2011@appspot.com as a buddy, and any IMs you send will be bounced back to you. OK, enough testing. Stop talking to yourself. 😉 As a next step I was going to try to implement an Eliza-type bot but as with most things these days just didn’t yet have the time.

Conclusion

In this post you learned how to leverage two more services available to you in the amazing Google App Engine platform, specifically the inbound mail and XMPP services. They’re extremely easy to set up, incredibly powerful, and with just a bit of servlet code in the middle this all plays very nicely with Open BlueDragon for GAE.

If you have comments or questions fire away, and if there are specific aspects of GAE you’d like to know more about (I have some additional posts in mind) please let me know. Thanks!

Using the Virtual File System and Image Service in Google App Engine with CFML

In my previous two posts in this series I offered up my introduction to Google App Engine and covered using the Google Datastore from CFML. In this post I’m going to cover using the Virtual File System (VFS) in Open BlueDragon for Google App Engine (GAE), and talk a bit about the GAE Image Service and how to leverage it in your CFML applications.

Uploading Files in Google App Engine Applications

One of the limitations in GAE is that your applications don’t have the ability to write to the file system. Not only was this a bit of a challenge to get CFML applications running at all on GAE since on-the-fly compiling and writing to the file system is at the heart of how CFML engines tend to work, this also prevents you from doing things like allowing your users to upload files to your application.

Necessity is the mother of invention, as the saying goes, and this case was no exception. To get around the inability to write to the file system, Vince Bonfanti created the virtual file system (VFS) project for GAE, which is an Apache Commons VFS plugin that creates a writeable filesystem on GAE by leveraging GAE’s datastore and memcache APIs. Note that the GAE VFS project is independent of OpenBD so if you are developing GAE apps in Java you can leverage the VFS as well.

In my previous post I went over pieces of the sample application I created for OpenCF Summit 2011, and in this post we’ll dig into one aspect of that application in detail so you’ll want to download the sample app (.tar.gz file, 15.3 MB) if you haven’t already. Unzip this file and import as a new project in Eclipse and you’ll be able to follow along as well as run the app from inside Eclipse.

Uploading Photos in the Sample Application

With the sample project running, pull up http://localhost:8888/photos.cfm in your browser.

Ocfs_sample_app_photos

Now in the sample application code, let’s take a look at the photos.cfm file in the war directory. Starting on line 60 you’ll see the photo upload form:


<form name="photoForm"
        action="_uploadPhoto.cfm"
        method="post"
        enctype="multipart/form-data">
    Photo: <input type="file" name="photo" /><br />
    <input type="submit" value="Upload" />
</form>

This is all completely standard stuff, and as you can see the form posts to _uploadPhoto.cfm. The first couple of chunks of _uploadPhoto.cfm look like this:


<cfif not DirectoryExists(ExpandPath('photos'))>
    <cfdirectory action="create" directory="photos" />
</cfif>

<cffile action="upload"
        destination="photos"
        filefield="photo" />

First we check to see if the photos directory exists and if it doesn’t, we use CFDIRECTORY to create it. Then we use CFFILE to upload the file.

At this point you’re probably scratching your head wondering what’s different from how you’d normally do things. That’s OK; we’ll get to the VFS magic in a bit. Just remember that without the VFS you wouldn’t be able to write to the GAE filesystem so you should be impressed that nothing looks different so far.

We’ll go over the rest of the code in _uploadPhoto.cfm in a bit, but go ahead and upload a photo on http://localhost:8888/photos.cfm so you have at least one photo in the applicaton. Once you upload a photo it just outputs all photos on that same screen so you should see something like this:

Ocfs_sample_app_photo_uploaded

 

 

Where Do Files Get Stored?

Now that we have a photo uploaded into the application, let’s take a look at where these files actually get stored and how to configure things so the VFS works in our CFML application running on GAE.

As mentioned above, the VFS uses the Google Datastore and Memcache APIs, so let’s open up our local Datastore browser and see what’s going on there. In your browser go to http://localhost:8888/_ah/admin and click on Datastore Viewer on the left.

Ocfs_sample_app_photo_entity

You’ll notice that in the Entity Kind drop-down there is an entry for /photos/your_file_name.jpg which indicates the photo is being stored in the Datastore, even though in the CFML code we’re doing what we’d normally do to write an uploaded file to the filesystem. If you click on “List Entities” for your photo’s Entity Kind you’ll notice that there are four records (at least in my case) for the file.

Ocfs_sample_app_photo_file_records

Why there are four records for this one file frankly I don’t know, and it’s not all that important to this discussion. At least that’s my excuse for not knowing at this point. 😉 Just realize that when you upload a file this is what happens in the Datastore as the GAE VFS handles the writing of the file.

Next select GaeFileObject as the Entity Kind in the Datastore viewer and click List Entities.

Gae_file_object_entities

Here you’ll see listed some of the directories that OpenBD uses to do its work behind the scenes, but you’ll also notice that there’s an entity with an ID/Name of /photos that has a filetype of “folder,” and there’s also an entity for the photo itself, and for that entity you’ll see that it includes the content size of the file and it has a filetype of “file.”

By default the VFS isn’t configured to allow you to upload to arbitrary directories, so let’s take a look at how to enable this in our application.

Configuring the VFS for File System Access

To enable the VFS for file uploads and other file system interaction, you need to add a servlet-mapping in your application’s web.xml file. This is how you tell your application that when certain URL patterns are used in your application that it’s going to be interacting with the VFS.

In Eclipse open up war/WEB-INF/web.xml and scroll down to line 87. You should see a comment block about the VFS:


<!--
    Configuring and mapping the GaeVfsServlet allows the Servlet/JSP engine (not the CFML engine) to
    "see" and serve application-generated static content (generated images, PDFs, uploaded files, etc...) that
    resides in a virtual file system location.
    See http://code.google.com/p/gaevfs
-->

By default the VFS servlet is commented out, so if you want to use the VFS in your applications you’ll need to uncomment the servlet block for the VFS, which in the sample application is lines 92 – 103 in web.xml

The next step is to add virtual directories as servlet mappings to web.xml so that the application knows to use the VFS servlet for specific URL patterns. On line 104 in web.xml you see the following:


<servlet-mapping>
    <servlet-name>gaevfs</servlet-name>
    <url-pattern>/photos/*</url-pattern>
</servlet-mapping>

In case you were wondering how we could reference a /photos director in our CFML code when that directory doesn’t actually exist on the file system, this is how. When a pattern of /photos/* is matched that work is handed off to the VFS servlet, which does its magic behind the scenes to allow you to use CFML tags such as CFFILE, CFDIRECTORY, CFLOG, and others without actually having write access to the file system.

Take another look at photos.cfm, and on line 48 you’ll see a CFDIRECTORY call:


<cfdirectory action="list" directory="photos" name="photos" />

<cfif photos.RecordCount gt 0>
    <h2>Smile! You're on OpenBD on GAE!</h2>
    <cfloop query="photos">
        <img src="photos/#photos.name#" /><br />
    </cfloop>
<cfelse>
    <p>No photos. Why don't you upload one?</p>
</cfif>

As you can see from that code CFDIRECTORY works exactly as you’d expect, returning a query object containing the directory listing from the VFS directory “photos.” If any photo files are found, they are then displayed using an image tag which also references the virtual photos directory.

Image Manipulation With the GAE Image Service

If you’ve perused the GAE documentation at all you’ll see that one of the many benefits of running your applciations on GAE is the amazing array of services avaialble on the GAE platform, one of which is an Image Service. (I’ll cover the mail and XMPP services in my next post.)

One of the interesting things to note about OpenBD for GAE is that it leverages many of these underlying services without you having to worry about it. For example, another restriction on GAE is that your application cannot make HTTP calls other than through the GAE URL Fetch API. What this means is that the CFHTTP tag on OpenBD for GAE uses the URL Fetch service under the hood without you having to do anything differently in your CFML code.

Let’s go a bit further in the _uploadPhoto.cfm file in the sample application. Since we don’t have any idea what size of image will be uploaded to the application, I decided to arbitrarily resize all images coming in to 300 x 200 pixels so they fit nicely on the page. Obviously if this were a real-world application we’d do some calculations so we could retain the correct aspect ratio for uploaded images and not resize at all unless they went beyond our desired boundaries, but for the purposes of the sample application I wanted to keep things simple.

After the file is uploaded using the CFFILE tag, the file is immediately read back from the VFS as binary data on line 9, which is necessary in order to manipulate the image using the GAE image service.


<cffile action="readbinary"
        file="#CFFILE.ServerFile#"
        variable="imgOrigData" />

In the next block of code we leverage the GAE image service to resize the image to 300 x 200 pixels:


<cfscript>
    isf = CreateObject("java", "com.google.appengine.api.images.ImageServiceFactory");

    imgSvc = isf.getImageService();
    imgOrig = isf.makeImage(imgOrigData);

    resize = isf.makeResize(300,200);

    imgNew = imgSvc.applyTransform(resize, imgOrig);

    imgNewData = imgNew.getImageData();
</cfscript>

At this point we have the resized image in the variable imgNewData, so the final step is to write that to disk using CFFILE, which of course is again leveraging the VFS:


<cffile action="write"
        file="#CFFILE.ServerFile#"
        output="#imgNewData#" />

We then use a CFLOCATION tag to send the user page to the photos.cfm page, which displays all the images in the /photos VFS directory.

That’s all for this post! I hope it provides some good information about the GAE VFS that’s included with OpenBD for GAE as well as giving a bit of an introduction to the services avaiable on GAE using the Image Service as an example.

As always if you have questions, corrections, etc. please post a comment. Next up is a post on the mail and XMPP services which I’ll have ready soon.

Using the Google App Engine Datastore with CFML

In my previous post I gave an intro on setting up the Google App Engine (GAE) plugin for Eclipse as well as installing Open BlueDragon for GAE. In this post I’m going to go over some of my sample application from OpenCF Summit 2011, specifically how CFML applications running on GAE interact with the Google Datastore.

I was initially going to cover the entirety of my sample application in one post but I think it’s going to be better to split this into smaller, more digestible chunks. I’ll start with the Google Datastore, in the next post I’ll address file uploads and image manipulation, and in yet another post I’ll cover the ability for your application to respond to inbound email as well as receive and send XMPP messages.

Let me preface all of this by stating unequivocally that I am not an expert in how the Google Datastore works, and that I’m going to focus on using it from OpenBD for GAE. What I hope this post will do is not only educate people who are just learning OpenBD for GAE, but also prompt discussions about features and functionality that doesn’t yet exist in OpenBD for GAE as it relates to the Datastore, or perhaps there is functionality that is present in OpenBD for GAE that people would like to see work differently.

The Sample Application

If you want to follow along and run things locally you’ll want to download the sample application Eclipse project (.tar.gz file, 15.3 MB). You should be able to unzip the file and then import it into Eclipse but please comment if you have any problems with the application files.

The application itself is pretty simple. It’s a quick session attendee application, and also has photo upload functionality but we’ll cover that in the next post. For now we’re going to focus on how to read and write data from the Google Datastore using the GAE-specific functionality that’s baked into OpenBD for GAE.

Once you import the project into Eclipse, right-click and choose Run As -> Web Application. After a few seconds you’ll see “The server is running” in the Eclipse console, at which point you can go to http://localhost:8888 in your browser and see this:

Ocfs_sample_app_home

Let’s add an attendee so you can get a feel for the very simple functionality of the application. Enter a first and last name (I’ll use my own name) and click the “Add Attendee” button. You’ll then see a bullet list at the top of the screen containing the names of attendees you add. You can clean everything out by clicking the “Delete All Attendees” link, and you can also search for attendees by first name, last name, or both.

As I mentioned above, we’ll cover the photo functionality in a future post.

Google Datastore Overview

As you add, delete, and search for attendees, as you might imagine this data is getting stored somewhere. We didn’t create a database or configure any datasources, however, so where is the data going?

The answer is the Google Datastore, which is the default data storage functionality for GAE. When you run a GAE project locally in Eclipse you get more or less the entire GAE environment, including a local version of the Google Datastore. As we’ll see in a moment, some GAE-specific functionality in OpenBD for GAE allows you to easily interact with the Google Datastore.

The Google Datastore is a schemaless, key/value datastore built on Google Bigtable. At a high level the Datastore can be lumped into the poorly named “NoSQL” database category. What this means is that as opposed to the relational databases and SQL queries that you may be used to, you’ll be storing what are called entities in the Datastore, which are objects organized by type or “kind,” and entities contain name/value pairs of data called properties. Properties in entities can be of various data types, including integer, float, string, date, binary data, and others. Entities also have an ID or key that uniquely identifies the entity in the Datastore.

Because the Datastore is schemaless, entities of the same kind do not necessarily have to contain all of the same properties. Using contact data as an example, you might store two entities that are both of kind “contact.” One contact might have a fax number where another might not. When storing these entities in the Datastore both entities could be defined with a kind (type) of “contact,” but the contact with the fax number would have a fax property, whereas the contact without a fax number wouldn’t have a fax property at all. In other words, the contact without a fax number would not have a fax property that was empty; rather, the fax property doesn’t necessarily exist in the contact without a fax number even though both entities are of kind “contact.”

Entities can be retrieved from the Datastore by key, by property values, or by querying the Datastore using GQL. GQL is a query language with some similarities to SQL, but given the nature of how the Datastore stores data there are of course important differences. We’ll be looking at some basic ways of interacting with the Datastore in your CFML applications in the next section of this tutorial.

For additional information about the Google Datastore, refer to:

Writing to the Google Datastore

Saving New Entities

In the same application we’ll be writing ColdFusion Components (CFCs) to the Datastore. OpenBD for GAE can save both CFCs and structs to the Datastore, and the simple datatypes contained in the value of struct keys, or in the variables scope of CFCs, are mapped to entity properties in the Datastore. Specifically, numbers, booleans, strings, dates, or arrays of these datatypes are what is currently able to be persisted to the Datastore by OpenBD for GAE.

Let’s take a look at how the simple attendee form data is stored to the Datastore. The form on the index page of the application is a standard HTML form with form fields firstName and lastName. The form posts to _addAttendee.cfm. On _addAttendee.cfm an instance of an Attendee CFC is created (you can see the code for the Attendee CFC in the sample application’s model directory), the form data is set to the CFC’s variables scope via the CFC’s init() method, and the CFC is then saved to the Datastore.


<!--- create attendee CFC and save it to google datastore --->
<cfset attendee = CreateObject("component",
            "model.Attendee").init(form.firstName, form.lastName) />
<cfset GoogleWrite(attendee) />

<!--- could also have done:
<cfset attendee.GoogleWrite() />
--->

<cflocation url="index.cfm" addtoken="false" />

What’s noteworthy in the code above is the use of the GoogleWrite() method, which is baked into OpenBD for GAE. This can be used as a top-level function to which a CFC or struct can be passed, or the base CFC in OpenBD for GAE includes a GoogleWrite() method so GoogleWrite() may be called on the CFC instance itself (as shown in the commented-out chunk of code above).

What happens behind the scenes when GoogleWrite() is called is the CFC becomes an entity in the Datastore, the data in the CFC’s variables scope–in this case firstName and lastName strings–become the entity’s properties, the entity is assigned a “kind” of attendee based on the CFC type (N.B. this is the CFC type, not the name of the variable being stored), and the entity is assigned a key as well as an ID/Name by the Datastore when it is saved.

You can view data stored in the Datastore using the GAE dashboard. The dashboard is available both locally as well as on the production GAE platform, but the live (non-local) version has a lot more options and information than the local version.

If you haven’t already done so, or if you deleted all your data, save a new attendee to the Datastore by filling out the form on the index page of the application and click the “Add Attendee” button.

Next, browse to the GAE dashboard at http://localhost:8888/_ah/admin :

Gae_local_dashboard_home

Click on the Datastore Viewer link on the left, then in the Entity Kind drop-down choose “attendee” and click List Entries:

Gae_datastore_entity_list

As mentioned above, the CFC type of attendee has become an entity kind in the Datastore, so any attendee CFCs you save will be put in this same bucket. A key and ID/Name has been assigned to the object, the firstName and lastName properties have been stored, and an additional field of org.openbluedragon.gae.keyname.cfc has been added, which has a value of model.Attendee. We’ll see this in action when we pull data from the Datastore in a moment, but this value is stored so the CFC can be reconstituted in your CFML code when it’s pulled from the Datastore. In other words when you pull this record back into CFML, you’ll get an instance of the Attendee CFC, and if you pull back multiple attendees, you’ll get an array of CFCs as opposed to a query object.

You can also save entities to the Datastore by explicitly specifying a kind and a key name. If you specify the key name when saving you will be able to pull the entity back using a combination of kind and key name as we’ll see when we get into retrieving data from the Datastore. If you don’t specify a key name when you save an entity to the Datastore, it’s auto-assigned an integer value but note that this auto-assigned value cannot be used to pull back the entity. Unless you specify a key name (which shows up in the ID/Name field in the Datastore viewer) you’ll have to use the unique key or query the Datastore to retrieve the entity.

Here’s a quick example of saving an Attendee CFC to the Datastore and explicitly specifying the kind and key name:


<cfset attendee = CreateObject("component", "model.Attendee").init("Homer", "Simpson") />
<cfset GoogleWrite(attendee, "attendee", "MyKeyName") />

This will save the attendee CFC as an entity of kind attendee with a key of “MyKeyName” in the Datastore. Note that if you do another GoogleWrite() using the same kind and key name, this will update the record with the key name specified. (More on updating entities in a moment.)

Now let’s write up a test page that saves a struct to the Datastore. This code is not included in the sample application download so you’ll be creating this file from scratch.

Right-click on the war directory in the project in Eclipse and choose New -> File. Call the file structtest.cfm (or whatever you want to call it), and enter the following code:


<cfscript>
foo = StructNew();
foo.foo = "bar";
foo.bar = "baz";

googleKey = GoogleWrite(foo, "MyNewKind");
</cfscript>

<cfoutput>googleKey = #googleKey#</cfoutput>

Since we’re not saving a CFC in this case, we have to provide a kind under which the Datastore will store this data. This is the second argument in the GoogleWrite() method, this first of which is obviously the data you wish to save. GoogleWrite() returns the key of the entity that was just saved and this is output in the final line.

With this struct data saved, go back to the dashboard, click on Datastore Viewer, and look at the Entity Kind drop-down. You’ll see your new “MyNewKind” available as an entity kind:

Gae_datastore_new_entity_kind

Choose MyNewKind in the entity kind drop-down and click “List Entities,” and you’ll see the struct data has been saved.

Gae_new_entity_kind_display

Because this is a struct and not a CFC, you’ll notice that there is no org.openbluedragon.gae.keyname.cfc property in this entity, since that isn’t needed to create a CFC instance when the data is returned.

Updating Existing Entities

Updating existing entities in the Datastore is done in one of two ways:

  1. Read the existing entity, update the properties that need to be updated, and write the modified entity back to the Datastore
  2. Write an entity directly to the Datastore (without reading first) using the entity kind and ID/name property

The way updates are handled in the Datastore is a bit different than the typical SQL update statements since you’re saving the entire entity again as opposed to updating discrete properties on the entity directly in the Datastore. When updating an entity in the Datastore, you’ll typically first want to read the entity from the Datastore, make the necessary updates to the entity’s properties, and then write the entity back to the Datastore.

For example, if I need to update the first name on an attendee entity with a key of ahBvcGVuY2ZzdW1taXQyMDExcg4LEghhdHRlbmRlZRgNDA I run the following code:


<cfscript>
    attendee = GoogleRead("ahBvcGVuY2ZzdW1taXQyMDExcg4LEghhdHRlbmRlZRgNDA");

    attendee.setFirstName("NewFirstName");

    GoogleWrite(attendee);
</cfscript>

The read/update/write steps may seem redundant but this does ensure that you’re updating the most recent version of the record, at least as of when you did the GoogleRead(). Many other “NoSQL” databases such as CouchDB take this same approach. CouchDB is also a schemaless, document-based datastore and it requires that you pass a version number of the document you are updating to ensure that you’re updating the latest revision of the document.

If you have written an entity and set an explicity ID/Name property you can update the entity by doing a GoogleWrite() and using this same ID/Name value:


<cfscript>
    attendee = CreateObject("component", "model.Attendee").init("NewFirstName", "NewLastName");

    GoogleWrite(attendee, "attendee", "MyExistingKeyName");
</cfscript>

Before moving on to retrieving data from the Datastore, a quick reminder about the schemaless nature of the Datastore. We could have specified a kind of “attendee” when saving the struct above, and it would have saved the struct as the same kind of entity as our attendee CFC, even though the data is not of the same type on the CFML side, and the two entities would not have any properties in common. Here again if you’re familiar with CouchDB, another schemaless, document-based datastore, this will sound familiar.

Reading From the Google Datastore

Retrieving Entities by Key

Now that we have some data in the Datastore, let’s look at the various ways in which the data can be retrieved, some of which were already introduced above.

The simplest data retrieval method is obviously to use a specific key to pull back a specific record. Since there isn’t an example of pulling back a specific record by key in the sample application, we’ll create another quick test file.

Right-click on the project’s war directory in Eclipse and choose New -> File. Call the file retrievebykey.cfm (or whatever you want). Next, open your GAE dashboard, go to the Datatstore Viewer, choose an Entity Kind of attendee, and click on List Entries. Copy the Key property from one of the entities and paste that value into the code below. My key is ahBvcGVuY2ZzdW1taXQyMDExcg4LEghhdHRlbmRlZRgNDA in the example.


<cfset attendee = GoogleRead('ahBvcGVuY2ZzdW1taXQyMDExcg4LEghhdHRlbmRlZRgNDA') />

<cfoutput>#attendee.getFirstName()# #attendee.getLastName()#</cfoutput>

The GoogleRead() function of OpenBD for GAE is used to retrieve entities by key. GoogleRead() takes a single key, an array of keys, or a kind and ID/name as arguments. Note that if kind and ID/name are used this is instead of using the key since the key is unique across entity kinds, whereas the ID/name value (an integer) is not.

Let’s play with this a bit more. If you only have one attendee in your Datastore add another, and view the attendee entities in your GAE dashboard again. Copy two keys and paste into this code (you can create a new file or use the same new file you created earlier):


<cfscript>
    keys = ArrayNew(1);
    keys[1] = 'ahBvcGVuY2ZzdW1taXQyMDExcg4LEghhdHRlbmRlZRgNDA';
    keys[2] = 'ahBvcGVuY2ZzdW1taXQyMDExcg4LEghhdHRlbmRlZRgQDA';
   
    attendees = GoogleRead(keys);
</cfscript>

<cfdump var="#attendees#" />

This will return an array of Attendee CFCs that match the keys in the array.

Retrieving Entities by Kind and Key Name (ID/Name)

Before moving on to querying the Datastore, let’s look at an example of pulling an entity back by kind and ID/name. When you look at the Datastore Viewer in the GAE dashboard, you’ll notice that all your entities are given an integer ID/name by default, which we discussed above. We also discussed the fact that you can explicitly assign an ID/Name value when you write an entity to the Datastore using GoogleWrite().

When retrieving entities by kind and ID/name, if you have explicitly assigned a value for the ID/name property you can retrieve by this value.


<cfset attendee = GoogleRead("attendee", "MyExistingKeyName") />
<cfdump var="#attendee#" />

The ID/name property is case insensitive, so MyExistingKeyName and myexistingkeyname (and all variants thereof) are the same as far as the Datastore is concerned.

Querying the Google Datastore

In the overview section above I mentioned that the Google Datastore uses a SQL-like language called GQL for Datastore queries. This is at the most raw level, however. When you’re using the Datastore through OpenBD for GAE, you’ll be querying the Datastore using a slightly different syntax than the raw GQL syntax, and it’s one based on JDOQL (Java Data Objects Query Language), which is not unlike other ORM-style languages such as Hibernate Query Language (HQL).

As explained on the Google Datastore wiki page on the OpenBD wiki, the syntax supported is actually a subset of JDOQL as follows:


SELECT FROM <kind>
[WHERE <filter>]
[ORDER BY <sort clause>]
[RANGE <from index>, <to index>]

All queries against the Datastore must start with SELECT FROM <kind> but all other parameters of the query are optional.

As an example, let’s first retrieve all entities of kind attendee from the Datastore. This example in a slightly different guise is contained in the sample application’s services.AttendeeService CFC, but here’s the very simple code:


<cfset allAttendees = GoogleQuery("SELECT FROM attendee") />

Note that the kind value (attendee in this case) is case-insensitive. This will return an array of attendee CFCs, not a query object. You may also use the CFQUERY tag and specify DBTYPE=”GOOGLE” to query the Datastore:


<cfquery name="allAttendees" dbtype="google">
  SELECT FROM attendee
</cfquery>

Here too the variable allAttendees will be an array of attendee CFCs, not a query object, even though the CFQUERY tag is being used.

Next let’s take a look at how to retrieve all attendees with the last name Smith.


<cfset theSmiths = GoogleQuery("SELECT FROM attendee WHERE lastName == 'Smith'") />

This should look rather familiar to those of us accustomed to SQL, but note the double equal sign (==) instead of the single equal sign you may be used to.

Multiple where clauses can be strung together using boolean operators. In this case we’ll get back any attendees with a firstName of John and a lastName of Smith:


<cfset allJohnSmiths = GoogleQuery("SELECT FROM attendee WHERE firstName == 'John' && lastName == 'Smith'") />

Note the && operator for “and,” and also be aware that the values of firstName and lastName must match exactly and are case sensitive.

Additional operators are available on numeric datatypes. Let’s assume our attendee entities included the attendees age, and we wanted to get an array of all attendees who are 40 or older:


<cfset oldsters = GoogleQuery("SELECT FROM attendee WHERE age >= 40") />

Finally, we can use the RANGE clause to limit the number of results we get back. Let’s say we only want to get back the first five John Smiths in the Datastore:


<cfset topFiveJohnSmiths = GoogleQuery("SELECT FROM attendee WHERE firstName == 'John' && lastName == 'Smith' RANGE 1, 6") />

The RANGE is one-based and the TO value in the range is not inclusive, hence the use of 1, 6 above to get the first 5 John Smiths in the Datastore.

Limitations

Limitations to querying the Datastore include:

  • Operators in the WHERE clause are limited to ==, >, >=, <, <=
  • Operators for or (||) and not equal to (!=) are not supported.
  • “Like” queries are not supported, meaning for example you cannot run a query that will return all attendees with a last name starting with S (in SQL terms, WHERE lastName LIKE ‘S%’). There are some efforts for creating full-text searching against the Datastore but none of these seem particularly mature at this point.

Deleting Entities From the Google Datastore

Deleting from the Datastore is simple. You use the GoogleDelete() function and pass in one of the following:

  • The key of the entity you want to delete
  • An array of keys of entities you want to delete
  • The object (CFC or struct) you want to delete
  • An array of objects (CFCs or structs) you want to delete

The base CFC in OpenBD for GAE also includes a GoogleDelete() function, so you may call GoogleDelete() directly on an instance of a CFC that has been persisted in the Datastore (e.g. myAttendee.GoogleDelete()).

Let’s look at a couple of examples.


<cfscript>
  // delete by key
  GoogleDelete("");

  // delete multiple records by key
  keys = ArrayNew(1);
  keys[1] = "";
  keys[2] = "";
  GoogleDelete(keys);

  // delete an attendee CFC; this assumes you have
  // done a read so the google key is in the CFC
  GoogleDelete(attendee);

  // delete multiple CFCs; assume attendees is an array
  // of attendee CFCs that have been read so the key is
  // included in each
  GoogleDelete(attendees);

  // call GoogleDelete() directly on an attendee CFC
  attendee.GoogleDelete();
</cfscript>

Examples From the Sample Application

I wound up spending a lot more time discussing the Google Datastore in general and its basic use from OpenBD for GAE than I originally intended, but I think going through things blow-by-blow is pretty important for both learning and reference purposes.

At this point the examples in the sample application are probably self-explanatory, so I’ll leave studying those and tracing the actions in the application and the interaction with the Google Datastore as an exercise for the reader.

As I said above what I’m really interested in doing with this post in addition to educating people is hearing from people who are using OpenBD for GAE if there is new functionality you’d like to see implemented, or existing functionality you’d like to see work differently.

In my next post, I’ll cover doing file uploads and using the Google App Engine image manipulation functionality, which will be a much shorter post than this one. 🙂

 

Intro to Google App Engine for Java and CFML Developers

At OpenCF Summit 2011 we were very lucky to have Chris Schalk from Google come present on Google App Engine. If you’re not familiar with Google App Engine (GAE) you should be! It’s an absolutely fantastic application platform as a service offering from Google with great functionality, very slick features, and incredibly generous quotas for free application hosting. And if you need to go beyond these quotas, you simply configure billing and pay nominal fees for what you use over the free quotas.

GAE lets you deploy Python and Java applications, but one of the most interesting things going on with Java these days is the numerous different languages that run on the JVM. The Java platform being available on GAE opens up some very cool options.

At OpenCF Summit I followed Chris’s presentation with one specific to Open BlueDragon on Google App Engine (GAE). OpenBD is a Java-based CFML runtime engine that allows you to deploy CFML applications to any standard servlet container, and also allows you to deploy your CFML applications to GAE. This is a great option for CFML developers since it’s a quick and easy–not to mention free for many apps!–way to get your CFML applications online without having to worry about setting up a server yourself or getting a hosting account. Not to mention that if you deploy your CFML apps on GAE you get the benefits of running on Google’s infrastructure and have on-demand scalability for your apps.

If you’re not familiar with CFML, it’s an incredibly powerful dynamic scripting language and framework that runs on the JVM. Think of it as a Java Tag Library on steroids. Even if you choose to build the backend of your applications in Java, CFML is a fantastic view layer language that’s a great alternative to JSP, it interacts seamlessly with Java code, and it makes a lot of things that are quite verbose in Java extremely quick and easy. Of course CFML is a full-fledged language as well so you can build entire applications in it quickly.

The tools available for GAE make it very easy to work with. If you use Eclipse, a great option is to grab the GAE plugin for Eclipse. This gives you the entire GAE environment that will run right inside Eclipse and let you develop and test locally. Then when you’re ready to deploy to GAE, it’s a right-click away.

We also have great tools for OpenBD. In addition to being able to grab the GAE edition of OpenBD and drop that into an Eclipse project, you can use the new OpenBD Desktop. This is a desktop application that runs on GNU/Linux, Mac, and Windows, and lets you set up a local development server in seconds. Once development is complete you can then deploy your CFML application to a standard JEE WAR, or you can deploy straight to GAE from OpenBD Desktop.

Openbd_desktop

In this post I’m going to cover getting up and running with GAE in Eclipse, and in my next post I’ll go over the demo application I built for my presentation at OpenCF Summit, and in that post I’ll highlight some of the cool features not only of OpenBD for GAE but GAE itself.

I’m going to cover how to set things up in Eclipse in this blog post, but I’ll have another how to and screencast covering OpenBD Desktop soon.

Installing the Google App Engine Plugin for Eclipse

I’m going to assume my audience is mostly Java or CFML developers who are already somewhat familiar with Eclipse, but if you need assistance with this piece of things please leave me a comment and I will be happy to help.

The GAE plugin for Eclipse installs in the same way as any other add-on for Eclipse. You simply open Eclipse, go to Help -> Install New Software and paste in the appropriate update site URL for your version of Eclipse. This will download everything you need to work with GAE from within Eclipse, including the GAE for Java SDK.

Once the plugin installs and you restart Eclipse, you’ll notice new Google icons in your Eclipse toolbar:

Gae_icons

As well as a new Google right-click menu:

Gae_right_click_menus

To create a new GAE project, you go to File -> New -> Project, and in the Google folder choose Web Application Project.

New_gae_project

You can then run your GAE application from within Eclipse by right-clicking the project and choosing Run As -> Web Application. Running in debug mode and all the other Java functionality with which you may be familiar is of course also available.

Note that because GAE is a platform as a service offering, the entirety of the Java world isn’t necessarily available to you. If you’re curious what is and isn’t available check the JRE Class Whitelist in the GAE docs.

Installing Open BlueDragon for GAE

With a new GAE project created in Eclipse, installing OpenBD for GAE is as easy as downloading a zip file, unzipping, and copying files into your GAE project’s war directory.

When you download and unzip OpenBD for GAE you’ll see these contents:

Openbd_gae_contents

If you’re new to OpenBD for GAE you’ll want to read the README files included.

To add OpenBD to your GAE project, go into the war directory in the unzipped OpenBD for GAE directory, and copy all the files in the OpenBD war directory into the war directory in your Eclipse GAE project. Note that you will overwrite any files with the same name in the Eclipse project, which is what you want to do.

What you do not want to do is delete all of the existing files in the war directory in the Eclipse project and have only the OpenBD GAE war files in the Ecliipse project. To put it another way, you are merging the OpenBD for GAE files with the files that are already in the Eclipse project, and any files with the same name will be replaced by the OpenBD for GAE files.

With these files in place, right-click on the project in Eclipse and choose Run As -> Web Application. You should see something similar to this in the Eclipse console:

Openbd_gae_console_output

You may see some warnings as well but these are typically harmless, and if you already have something running on port 8888 you’ll want to shut that down before launching the OpenBD GAE application.

If everything started up successfully you can then navigate to http://localhost:8888 in a browser and see this:

Openbd_gae_welcome_page

You’re now all set to build CFML applications for GAE!

Working with CFML Code

Working with CFML code in an OpenBD for GAE project is no different that typical CFML development. The only real thing you need to be aware of is that your CFML code must be placed in the war directory in your Eclipse project. This is the root of your application. (Note that if you haven’t worked with CFML or perhaps use a CFML editor other than Eclipse, you’ll want to install CFEclipse, which is a great open source CFML plugin for Eclipse.)

Let’s add a CFML file to our project so you can get a feel for working with CFML code in the context of an OpenBD for GAE project.

In your Eclipse project right-click the war directory and choose New -> File and name the file test.cfm. In this newly created file, add the following code:

<cfset name = "Matt" /> <cfoutput>Hello #name#! Today is #DateFormat(Now())#.</cfoutput>

Save the file, and then go to http://localhost:8888/test.cfm in your browser. You should see this:

Openbd_gae_test_file

That’s all there is to it. You can now build CFML applications as usual using OpenBD for GAE.

Up until recently there have been some differences in supported syntax and functionality between “regular” OpenBD and OpenBD for GAE, but as of the next release of OpenBD the regular Java edition and the GAE edition will have the same exact functionality available, other than where specific functionality is not allowed on the GAE platform. The current nightly builds of OpenBD are based on this new unified codebase between the two editions of OpenBD.

Most CFML code will work fine on OpenBD for GAE. For example, the Mach-II framework as well as ColdSpring both work perfectly, and these frameworks are being used for the open source Enlist application that we started developing during the hackfest at OpenCF Summit.

What’s Next?

Probably the major thing developers will run into immediately when building apps for GAE is that a traditional relational database is not available other than through Google App Engine for Business. If you aren’t on the GAE for Business platform, you’ll be using the Google Datastore, which is a high-performance, highly scalable key-value (“NoSQL”) datastore that can be accessed via JDO or JPA, and also in CFML via GAE-specific functionality built into OpenBD for GAE.

I’ll cover the Google Datastore as well as some of the amazing features of the GAE platform (including receiving mail and receiving/sending XMPP messages) in my next post.

Quick Tip on Logging with Java on Google App Engine

I’m in the process of messing around with some really cool stuff on Google App Engine (wonder why …) and I ran into something that I didn’t see covered in the docs (which as a rule are excellent). I came across the solution in a sample app for GAE that solved the problem so I thought I’d share.

Setting up logging in a servlet is pretty straight-forward, particularly if you’re using the Eclipse Plugin for GAE since it more or less configures it for you. Here’s a quick example. This is dummy code obviously, but pay attention to the package delcaration.

package org.opencfsummit;

import  java.util.logging.Logger;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 
import java.servlet.ServletException; 

public class MyServlet extends HttpServlet {

    private static final Logger log = Logger.getLogger(MyServlet.class.getName());

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // do whatever else your doPost method needs to do here, and write some info to the log
        log.info("I'd like to write this to the log, please.");

    }

}

That all seemed well and good, but when I looked for my log entries in the GAE admin console, nothing was getting logged.

Well, turns out that even though the Eclipse plugin sets up the basic logging configuration for you, there’s a bit of additional configuration needed related to the package in which the class you’re logging from resides.

The default WEB-INF/logging.properties file contains this:

# Set the default logging level for all loggers to WARNING
.level = WARNING

Now what didn’t make sense to me until I found an example and tried it was why my log.info() calls weren’t doing anything. Maybe I’m missing something, but I had to add this to logging.properties to get things to log:

org.opencfsummit.level = INFO

Now why if you’re explicitly calling log.info() it wouldn’t log the information at the info logging level I’m not sure, but adding my package name and a level to logging.properties definitely took care of the issue. 

Google App Engine for Business 101 #s2gx

How to Build, Manage & Run Your Business Applications on Google’s Infrastructure
Christian Schalk – Developer Advocate, Google

  • not really an advocacy position
  • still in engineering, but work a lot more with users directly
  • go out to companies to help them be successful

What is cloud computing?

  • lots of different definitions
  • pyramid of (bottom up): 
    • infrastructure as a service 
      • joyent, rackspace, vmware, amazon web services
      • provides cooling, power, networking
    • application platform as a service 
      • GAE falls in this category
      • tools to build apps
    • software as a service 
      • google docs, etc.

GAE

  • easy to build
  • easy to maintain
  • easy to scale 
    • appengine resides in google’s overall infrastructure so will scale up as needed
  • started with only python
  • with java support, opened the doors for java enterprise developers

By the Numbers

  • launched in 2008
  • 250,000 developers
  • 100,000+ apps
  • 500M+ daily pageviews 
    • 19,000 queries per second — has almost doubled since January

Some Partners

  • best buy
  • socialwok
  • xylabs
  • ebay
  • android developer challenge
  • forbes
  • buddypoke 
    • 62 million users
  • gigya 
    • do social integration for large media events (movie launches, sports events) — huge spikes in traffic so GAE just handles it
  • ubisoft
  • google lab
  • ilike
  • walk score
  • gigapan
  • others
  • point here is it’s very easy to drop specific apps on GAE without running litearlly everything on GAE
  • very popular among social networking apps because of easy scalability

Why App Engine?

  • managing everything is hard
  • diy hosting means hidden costs 
    • idle capacity
    • software patches & upgrades
    • license fees
  • “cloud development in a box”

App Engine Details

  • collection of services 
    • memcache, datastore, url fetch, mail, xmpp, task queue, images, blobstore, user service
  • ensuring portability — follows java standards 
    • servlets -> webapp container
    • jdo/jpa -> datasource api
    • java.net.URL -> URL fetch
    • javax.mail -> Mail API
    • javax.cache -> memcache
  • extended language support through jvm 
    • java, scala, jruby, groovy, quercus (php), javascript (rhino)
  • always free to get started
  • liberal quotas for free applications 
    • 5M pageviews/month
    • 6.5 CPU hours/day

Application Platform Management

  • download and install SDK 
    • Eclipse plugin also available
  • build app and then deploy to the public GAE servers
  • app engine dashboard
  • app engine health history 
    • shows status of each service individually across GAE as a whole

Tools

  • google app engine launcher for python
  • sdk console 
    • local version of the app engine dashboard
  • google plugin for eclipse 
    • wizard for building new app engine apps
    • can run the entire gae environment locally within eclipse
    • easy deployment to app engine servers
    • in process of building a new version of this with more features

Continuously Evolving

  • aggressive schedule for providing new features
  • may 2010 — app engine for business announced

What’s New?

  • multi-tenant apps with namespace API
  • high performance image serving
  • openid/oauth integration
  • custom error pages
  • increased quotas
  • app.yaml now usable in java apps
  • can pause task queues
  • dashboard graphs now show 30 days
  • more — see http://googleappengine.blogpost.com

Getting Started

Creating and Deploying an App

  • demoing eclipse plugin
  • can create a new Google Web Application, optionally with GWT
  • projects follow the typical java webapp structure
  • before deployment, can test/debug locally just like any Java project in eclipse
  • even the datastore is available locally for development/testing
  • new features tend to be introduced in python first, then java gets them later
  • to deploy, right click the project, choose “google,” then deploy 
    • this brings up a window where you put in your application ID and version, then uploads to the GAE servers
  • can log into GAE dashboard and configure billing with maximum charges if your app will exceed the free quotas
  • can use your own custom domains, this ties into google apps
  • can assign additional developers to GAE applications by email address
  • can deploy new versions of applications and keep the old ones as well, can toggle between versions and choose one as default

What about business applications?

  • GAE for Business
  • same scalable cloud hosting platform, but designed for the enterprise
  • not production quite yet
  • enterprise application management 
    • centralized domain console (preview available today)
  • enterprise reliability and support 
    • 99.9% SLA
    • direct support 
      • tickets tracked, phone support, etc.
  • hosted SQL (preview available today) 
    • managed relational sql database in the cloud
    • doesn’t replace the datastore–available in addition to the datastore
  • ssl on your domain 
    • current core product doesn’t offer this
  • secure by default 
    • integrated single signon
  • pricing that makes sense 
    • apps cost $8/user, up to a max of $1000 per month

Enterprise App Development With Google

  • GAE for Business
  • Google Apps for Business
  • Google Apps Marketplace
  • Firewall tunneling technology available (Secure Data Connector)

App Engine for Business Roadmap

  • enterprise admin console (preview)
  • direct support (preview)
  • hosted sql (limited release q4 2010)
  • sla (q4 2010)
  • enterprise billing (q4 2010)
  • custom domain ssl (2010 – 2011)

SQL Support

  • can run this all locally in eclipse
  • demo of spring mvc travel app running on GAE with the SQL database 
    • have to explicitly enable sessions
    • had to disable flow-managed persistence

Become an App Engine for Business Trusted Tester!

Facebook API Error Code 100: “Next is not owned by the application”

Since we’re going to open registration for OpenCF Summit before long and launch what I’m calling our “Engage” application for OpenCF Summit (the name may change), I decided to dig into the Facebook API a bit so we can let people sign in using their Facebook account. We’ll also be supporting Twitter and Google sign-ons, but Facebook seemed as good a place as any to start since I saw The Social Network last night (which was completely amazing by the way).

Since the vast majority of my apps at work are behind a firewall this is my first foray into integrating any of the social networks’ logins into my own applications. Facebook makes it dead simple to get going, but once I registered my application and tried the login button, I was getting the following error:

API Error Code: 100
API Error Description: Invalid parameter
Error Message: next is not owned by the application.

I did some searching and came up with a bunch of potential solutions that didn’t seem to be relevant any longer since the settings they suggested changing don’t exist anymore. After a bit of poking around on my application settings on Facebook I noticed my site domain on the Web Site settings tab was blank. I put opencfsummit.org in there (since I’ll want the login to apply to all subdomains on that domain), and that resolved the problem for me (see screenshot).

The other thing I was testing with this was to make sure everything worked from Google App Engine, since we may incorporate the Engage app with the main web site, which runs on Open BlueDragon for Google App Engine. I was pleased to see everything worked perfectly, at least so far.

I’m sure some of the other solutions I found will work in other situations, but since none of them seemed to apply for me and this was a fresh application with Facebook’s own sample code, I thought someone else might run into this same issue and figured I’d share.

Open BlueDragon on Google App Engine – Sample App and Presentation PDF

This is long-delayed after cf.Objective() 2010, but here is a zip of the sample app and the presentation PDF from the presentation Peter and I gave on running CFML applications on Google App Engine.

We also gave this presentation at the CFMeetup a couple of weeks ago (you can watch the recording), and are doing it again for the Mid-Michigan CFUG on Tuesday, June 8, at 7 pm Eastern US time.

To use the sample app create a new Google App Engine project in Eclipse, then copy the unzipped files into that project.

If you need help getting up and running with GAE on Eclipse, check this blog post on the Detroit Area Adobe UG’s blog, or check the GAE for Java page. The MMCFUG may also be streaming this meeting live so I’ll post again with a URL if that happens.

I didn’t add this to the PDF or code before I uploaded them, but both are released under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. Creative Commons License

openbd_gae_sample_app.zip
Download this file

OpenBD_on_GAE.pdf
Download this file

CFMeetup this Thursday! “Living in the Cloud: CFML Apps on Google App Engine”

Our 12pm (US ET) talk on Thursday May 20 will be “Living in the Cloud: CFML Apps on Google App Engine”, with Matt Woodward & Peter Farrell.

TOPIC DESCRIPTION: (provided by the speaker)

If you want to take advantage of the power of cloud computing but want to focus on applications instead of server infrastructure, you owe it to yourself to check out Google App Engine. Google App Engine lets you deploy applications to Google’s infrastructure with the push of a button, and the best part is that for many applications it’s entirely free of cost.

In this presentation we’ll discuss both the benefits and downsides of living in the cloud, outline how Google App Engine differs from other cloud solutions, and demonstrate how to build and deploy a simple CFML application to Google App Engine using Open BlueDragon, which is the only CFML engine compatible with Google App Engine.

If you’re interested in running your CFML applications in the cloud come get in on the ground floor, because with a few simple tips and tricks, it’s all clear skies.

Peter Farrell and I will be doing our OpenBD on Google App Engine presentation from cf.Objective() on the CFMeetup this Thursday at noon Eastern. See you there!

Using OpenBD on Google App Engine? Please let me know!

Peter Farrell and I are working on our "Living in the Cloud: CFML Applications on Google App Engine" presentation for cf.Objective(), and we'd love to include a mention of any sites out in the wild that are using OpenBD on GAE. So if you're using OpenBD on GAE for production sites or even just some experimentation with all the cool possibilities available on GAE, please let me know!

You can leave a comment here or send an email to matt at mattwoodward dot com. Thanks!