A Better way to serve files from the Google App Engine Virtual File System

Web Development, BlueDragon, Google App Engine

The other day I posted an example of how one might access images, for example, from your Google App's virtual file system.  While it was sufficient, I wasn't really happy with how the URL's looked and how missing files were managed. 

Right as I was writing this post to detail how I had rewritten the url to manage accessing VFS files, Vince posted this to the openBD mailing list...rendering my solution obsolete! 

Quoted from the mailing list:

My apologies for taking so long to respond to this thread. In addition to Aaron's "getfile.cfm"--a very nice solution--GaeVFS contains a built-in servlet that allows you to do directory listings and serve files from configured directories. In order to use the GaeVfsServlet, add the following to your web.xml (this example serves files from the "/images" directory of your webapp):
 
    <servlet>
        <servlet-name>gaevfs</servlet-name>
        <servlet-class>com.newatlanta.commons.vfs.provider.gae.GaeVfsServlet</servlet-class>
        <init-param>
            <param-name>dirListingAllowed</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>initDirs</param-name>
            <param-value></param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>gaevfs</servlet-name>
        <url-pattern>/images/*</url-pattern>
    </servlet-mapping>
 
You can then serve files by using normal IMG tags:
 
    <img src="/images/mypicture.jpg">
 
You can serve files from as many directories as you'd like by adding multiple <servlet-mapping> elements and specifying the appropriate <url-pattern> elements. Also note the "dirListingAllowed" init parameter which enables/disable directory listings. Further details are available in the javadoc comments in the source code:
 
 
tags:
cloud

Url Rewriting on Google App Engine

Web Development, BlueDragon, Google App Engine

Lately I have been digging in to application development for the Google App Engine running Open BlueDragon.  I encountered a need to rewrite and filter some URL's. 

The software:  UrlRewriteFilter  (go get it here)  I used the Beta 3.2 version.

The Installation: (borrowed in part from tuckey.org's instructions)

  1. Move the urlrewrite.xml to the /war/WEB-INF directory.
  2. Move the urlrewrite-3.2.0.jar to the /war/WEB-INF/lib directory.
  3. Add the following to your /war/WEB-INF/web.xml.
            <filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  4. Add your own configuration to the /war/WEB-INF/urlrewrite.xml that was created.
  5. Re-deploy your Google App.

Examples:

     <!--Redirect one url-->
        <rule>
            <from>/some/old/page.html</from>
            <to type="redirect">/very/new/page.html</to>
        </rule>

  <!--  Redirect a directory -->
        <rule>
            <from>/some/olddir/(.*)</from>
            <to type="redirect">/very/newdir/$1</to>
        </rule>

   <!-- Clean a url -->
        <rule>
            <from>/products/([0-9]+)</from>
            <to>/products/index.jsp?product_id=$1</to>
        </rule>
   <!--
    eg, /products/1234 will be passed on to /products/index.jsp?product_id=1234 without the user noticing.
   -->
    <!-- Browser detection -->
        <rule>
            <condition name="user-agent">Mozilla/[1-4]</condition>
            <from>/some/page.html</from>
            <to>/some/page-for-old-browsers.html</to>
        </rule>

tags:
cloud

Coldfusion on the Google App Engine with Open BlueDragon

ColdFusion, Web Development, BlueDragon, Internet, Google App Engine

The future is now! 

A little melodramatic maybe, but this technology is exciting.  Free cfml app servers with clustering (including data and file storage). 

First, if you don't know what the Google App Engine is yet, go here first and do a little reading.  Once you have read enough of that to be sufficiently excited, we need to set up the development and deployment tools.  Paul Kukiel has put together a really nice demo on how to do this hereNOTE THERE IS ONE THING THAT IS INCORRECT IN THE VIDEO   Do not delete the "war" directory, merely paste the openbd war over the existing one.  This is important.

Next, reading and writing data with the Google datastore. 

Storing data in a scalable web application can be tricky. A user could be interacting with any of dozens of web servers at a given time, and the user's next request could go to a different web server than the one that handled the previous request. All web servers need to be interacting with data that is also spread out across dozens of machines, possibly in different locations around the world.
Thanks to Google App Engine, you don't have to worry about any of that. App Engine's infrastructure takes care of all of the distribution, replication and load balancing of data behind a simple API—and you get a powerful query engine and transactions as well.

Thanks to the fine people at Open BlueDragon, this task is made very very simple.  Every cfc in the openBD GAE inherits the following methods from component.cfc.  GoogleWrite(), GoogleRead(), and GoogleKey().

 

-- Example object Status.cfc:

<cfcomponent displayname="Status" output="false">

	<cfproperty name="Message" displayname="Message" type="string" />
	<cfproperty name="DateTimeCreated" displayname="DateTimeCreated" type="date" />

	<cffunction name="init" access="public" output="false" returntype="Status">
		<cfreturn this/>
	</cffunction>

	<cffunction name="getMessage" access="public" output="false" returntype="string">
		<cfreturn this.Message />
	</cffunction>

	<cffunction name="setMessage" access="public" output="false" returntype="void">
		<cfargument name="Message" type="string" required="true" />
		<cfset this.Message = arguments.Message />
		<cfreturn />
	</cffunction>

	<cffunction name="getDateTimeCreated" access="public" output="false" returntype="date">
		<cfreturn this.DateTimeCreated />
	</cffunction>

	<cffunction name="setDateTimeCreated" access="public" output="false" returntype="void">
		<cfargument name="DateTimeCreated" type="date" required="true" />
		<cfset this.DateTimeCreated = arguments.DateTimeCreated />
		<cfreturn />
	</cffunction>

	
</cfcomponent>

 

-- Writing data to the datastore:

<cfscript>
//saving a new Status to Google datastore
Status = createObject( "component", "model.Status" ).init();
Status.setMessage( "I love Google App Engine and OpenBD!" );
Status.setDateTimeCreated( Now() );

/*now all we do is call the googleWrite() method on our object, notice this returns the objects new google key*/
googleKey = Status.googleWrite();
</cfscript>

 

-- Querying the datastore:  for more on this visit the openBD wiki page on the datastore

<!---
notice dbtype="google" and the quasi-SQL 
--->
<cfquery dbtype="google" name="result">
Select from Status
</cfquery>

<!---
The result of this query, is an array of matching Status objects.  Not the usual query recordset.
--->

 

Securing your new web app with the UserServiceFactory (com.google.appengine.api.users.UserServiceFactory)

Once I figured this step out, it was almost embarassingly easy to secure a page, allowing access only to validated Google account holders.

<cfscript>
UserServiceFactory = CreateObject("java","com.google.appengine.api.users.UserServiceFactory");

User = UserServiceFactory.getUserService().getCurrentUser();

/*Here I am doing a test to see if there is a valid user object returned, aka "logged in".  At this time, I haven't found the ideal solution for this*/

isLoggedIn = false;

try{
   user.getEmail();
   isLoggedIn = true;
}
catch (any excpt){}

</cfscript>

<!---

building login/logut links

--->

<cfif NOT isLoggedIn>
YOU NEED TO <a href="<cfoutput>#UserServiceFactory.getUserService().createLoginURL(toString("http://#cgi.SERVER_NAME#"))#</cfoutput>">LOGIN</a>
<cfelse>
	<cfoutput>#request.user.getEmail()#</cfoutput>:  All your email are belong to us 
	<br />
	<a href="<cfoutput>#UserServiceFactory.getUserService().createLogoutURL(toString("http://#cgi.SERVER_NAME#"))#</cfoutput>">LOGOUT</a>
</cfif>

 

Time to build some real applications.  Early indications from some experimentation by Dave Shuck, are revealing that the Mach-ii MVC framework along with the Coldspring IOC framework are working on the Google App Engine.

Other features, new or otherwise:

 

There is just no reason that we as cfml developers shouldn't be churning out app after app on this platform. 


Search

Fuelly