Lightweight


                  on the

by Tim Berglund
Tell me about
aGreat
Application
  Language
Tell me

a
   Happy
    Tale
      of
Deployment
and


Make  it

   Fast
Tell me about

the
      Googl
        eApp
         Engine
An App Server
In the CLoud
Google
Infrastructure
Usually Free!
Quotas




http://code.google.com/appengine/docs/quotas.html
Quotas




http://code.google.com/appengine/docs/quotas.html
Pricing
Languages
Languages
Languages
Languages
Services
Services


It’s an app server
Services


With a few extra
    features
Services
Services
Datastore
Services
Datastore
Authentication
Services
Datastore
Authentication
Caching
Services
Datastore
Authentication
Caching
XMPP
Services
Datastore
Authentication
Caching
XMPP
Email
Services
Datastore         Task Queue
Authentication
Caching
XMPP
Email
Services
Datastore         Task Queue
Authentication    Image API
Caching
XMPP
Email
Services
Datastore         Task Queue
Authentication    Image API
Caching           URL Fetching
XMPP
Email
Services
Datastore         Task Queue
Authentication    Image API
Caching           URL Fetching
XMPP              OAuth
E...
Services
Datastore         Task Queue
Authentication    Image API
Caching           URL Fetching
XMPP              OAuth
E...
But It’s not Perfect
Limitations
Limitations
The JDK whitelist
Limitations
The JDK whitelist
  http://code.google.com/appengine/docs/java/jrewhitelist.html
Limitations
The JDK whitelist
  http://code.google.com/appengine/docs/java/jrewhitelist.html

No Hibernate
Limitations
The JDK whitelist
  http://code.google.com/appengine/docs/java/jrewhitelist.html

No Hibernate
  Only JPA and ...
Limitations
The JDK whitelist
  http://code.google.com/appengine/docs/java/jrewhitelist.html

No Hibernate
  Only JPA and ...
Limitations
The JDK whitelist
  http://code.google.com/appengine/docs/java/jrewhitelist.html

No Hibernate
  Only JPA and ...
Tell me about
Groovy-based
Groovy-based
Lightweight
Groovy-based
Lightweight
Page-centric
Groovy-based
Lightweight
Page-centric
Tightly coupled to the Google App Engine
Groovy-based
Lightweight
Page-centric
Tightly coupled to the Google App Engine
A better GAE than the GAE
Setting up Gaelyk
Serving Content
Serving Content
Serving Content


Static content (like in a WAR)
Serving Content


Static content (like in a WAR)
Groovy templates
Templates
<% include '/WEB-INF/includes/header.gtpl' %>

<h1>Look Up an Artist</h1>

<form action="/artistLookup.groovy" m...
Templates
<% include '/WEB-INF/includes/header.gtpl' %>

<h1>Look Up an Artist</h1>

<form action="/artistLookup.groovy" m...
Templates
<% include '/WEB-INF/includes/header.gtpl' %>

<h1>Look Up an Artist</h1>

<form action="/artistLookup.groovy" m...
Templates
<% include '/WEB-INF/includes/header.gtpl' %>

<h1>Look Up an Artist</h1>

<form action="/artistLookup.groovy" m...
Templates
<% include '/WEB-INF/includes/header.gtpl' %>

<h1>Look Up an Artist</h1>

<form action="/artistLookup.groovy" m...
Templates
Templates

Lightweight, Groovy JSPs
Templates

Lightweight, Groovy JSPs
Downside: Scriptlets
Templates

Lightweight, Groovy JSPs
Downside: Scriptlets
Request attributes bound from Groovlets
Groovlets
import java.net.URLEncoder

if(params.artist) {
  def response = urlFetch.fetch(new URL("http://musicbrainz.org/...
Groovlets
Groovlets
Groovy script, meet Servlet
Groovlets
Groovy script, meet Servlet
Intrinsic variables
Groovlets
Groovy script, meet Servlet
Intrinsic variables
Forwarding
Groovlets
Groovy script, meet Servlet
Intrinsic variables
Forwarding
Redirecting
Groovlets
Groovy script, meet Servlet
Intrinsic variables
Forwarding
Redirecting
MarkupBuilder
import java.net.URLEncoder

if(params.artist) {
  def response = urlFetch.fetch(new URL("http://
musicbrainz.org/ws/1/arti...
import java.net.URLEncoder

if(params.artist) {
  def response = urlFetch.fetch(new URL("http://
musicbrainz.org/ws/1/arti...
import java.net.URLEncoder

if(params.artist) {
  def response = urlFetch.fetch(new URL("http://
musicbrainz.org/ws/1/arti...
import java.net.URLEncoder

if(params.artist) {
  def response = urlFetch.fetch(new URL("http://
musicbrainz.org/ws/1/arti...
import com.google.appengine.api.datastore.*
import static com.google.appengine.api.datastore.FetchOption

if(!user) {
  re...
import com.google.appengine.api.datastore.*
import static com.google.appengine.api.datastore.FetchOption

if(!user) {
  re...
import com.google.appengine.api.datastore.*
import static com.google.appengine.api.datastore.FetchOption

if(!user) {
  re...
import com.google.appengine.api.datastore.*
import static com.google.appengine.api.datastore.FetchOption

if(!user) {
  re...
import com.google.appengine.api.datastore.*
import static com.google.appengine.api.datastore.FetchOption

if(!user) {
  re...
import com.google.appengine.api.datastore.*
import static com.google.appengine.api.datastore.FetchOption

if(!user) {
  re...
URL Mapping
URL Mapping

Templates in war/*.gtpl
URL Mapping

Templates in war/*.gtpl
Groovlets in war/WEB-INF/groovy/*.groovy
URL Mapping

Templates in war/*.gtpl
Groovlets in war/WEB-INF/groovy/*.groovy
Pretty URLs with
war/WEB-INF/routes.groovy
The Datastore
The Datastore
The Datastore
Google’s BigTable infrastructure
The Datastore
Google’s BigTable infrastructure
Schemaless
The Datastore
Google’s BigTable infrastructure
Schemaless
Named entities (property bundles)
The Datastore
Google’s BigTable infrastructure
Schemaless
Named entities (property bundles)
Indexed, queryable, sortable
The Datastore
Google’s BigTable infrastructure
Schemaless
Named entities (property bundles)
Indexed, queryable, sortable
T...
The Datastore
Google’s BigTable infrastructure
Schemaless
Named entities (property bundles)
Indexed, queryable, sortable
T...
Datastore Indexes
Datastore Indexes
Automatically generated by default
Datastore Indexes
Automatically generated by default
Override in WEB-INF/datastore-indexes.xml
Datastore Indexes
      Automatically generated by default
      Override in WEB-INF/datastore-indexes.xml
<?xml version="...
Tell me about

  Other
      Services
Email   in Java
Email
                               with Gaelyk


mail.send sender: 'story-admin@augusttechgroup.com',
          to: 'tlb...
Inbound Email
Inbound Email

Enable in appengine-web.xml
Inbound Email

Enable in appengine-web.xml
Enable built-in servlet in web.xml
Inbound Email

Enable in appengine-web.xml
Enable built-in servlet in web.xml
email.groovy Groovlet
Inbound Email

Enable in appengine-web.xml
Enable built-in servlet in web.xml
email.groovy Groovlet
The “message” intrinsi...
Memcache
      in Java
Memcache
                             with Gaelyk

def countryFr = new Country(name: 'France')

memcache['FR'] = countryFr...
URL Fetch
        in Java
URL Fetch
                                     with Gaelyk



def response = urlFetch.fetch(new URL("http://example.com"))...
Task Queues

queue.add countdownMillis: 10000,
          url: '/task/emailTaskList',
          taskName: 'Email current st...
Task Queues
Task Queues

Timed HTTP requests
Task Queues

Timed HTTP requests
Configure in war/WEB-INF/queue.xml
Task Queues

Timed HTTP requests
Configure in war/WEB-INF/queue.xml
 http://code.google.com/appengine/docs/java/config/queue...
Task Queues

Timed HTTP requests
Configure in war/WEB-INF/queue.xml
 http://code.google.com/appengine/docs/java/config/queue...
Task Queues

Timed HTTP requests
Configure in war/WEB-INF/queue.xml
 http://code.google.com/appengine/docs/java/config/queue...
XMPP
XMPP

User notification
XMPP

User notification
XML payloads for distributed communication
XMPP

User notification
XML payloads for distributed communication
Send messages with a Groovier API
XMPP

User notification
XML payloads for distributed communication
Send messages with a Groovier API
Receive messages throu...
XMPP Sending
         in Java
XMPP Sending
        with Gaelyk
XMPP Sending
                                      with Gaelyk

def recipient = 'tlberglund@gmail.com'
if (xmpp.getPresenc...
XMPP Sending
                                      with Gaelyk

def recipient = 'tlberglund@gmail.com'
if (xmpp.getPresenc...
XMPP Sending
                                      with Gaelyk

def recipient = 'tlberglund@gmail.com'
if (xmpp.getPresenc...
XMPP Receiving
XMPP Receiving

Enable in appengine-web.xml
XMPP Receiving

Enable in appengine-web.xml
Enable built-in servlet in web.xml
XMPP Receiving

Enable in appengine-web.xml
Enable built-in servlet in web.xml
/war/WEB-INF/groovy/jabber.groovy
XMPP Receiving

Enable in appengine-web.xml
Enable built-in servlet in web.xml
/war/WEB-INF/groovy/jabber.groovy
The “mess...
Plugins
Plugins
Plugins
Analogous to Grails plugins
Plugins
Analogous to Grails plugins
Mini Gaelyk apps
Plugins
Analogous to Grails plugins
Mini Gaelyk apps
plugins/xxxPluginDescriptor.groovy
Plugins
Analogous to Grails plugins
Mini Gaelyk apps
plugins/xxxPluginDescriptor.groovy
Bundled as ZIP files
Plugins
Analogous to Grails plugins
Mini Gaelyk apps
plugins/xxxPluginDescriptor.groovy
Bundled as ZIP files
Ad-hoc discove...
Development
What about


      Services
      in development?
GAE Emulation
GAE Emulation
Datastore simulated in filesystem
GAE Emulation
Datastore simulated in filesystem
General Administration
GAE Emulation
Datastore simulated in filesystem
General Administration
  http://localhost:8080/_ah/admin
GAE Emulation
Datastore simulated in filesystem
General Administration
  http://localhost:8080/_ah/admin
Authentication
GAE Emulation
Datastore simulated in filesystem
General Administration
  http://localhost:8080/_ah/admin
Authentication
  h...
GAE Emulation
Datastore simulated in filesystem
General Administration
  http://localhost:8080/_ah/admin
Authentication
  h...
Code
On github

git@github.com:tlberglund/august-stories.git

git@github.com:tlberglund/august-demo.git
Thank You
             Tim Berglund
         www.augusttechgroup.com
     tim.berglund@augusttechgroup.com
               ...
Photo Credits
Parchment Background
http://www.photoshopstar.com/effects/recreate-indiana-jones-text-effect/
Gaelyk: Lightweight Groovy on the Google App Engine
Gaelyk: Lightweight Groovy on the Google App Engine
Gaelyk: Lightweight Groovy on the Google App Engine
Gaelyk: Lightweight Groovy on the Google App Engine
Gaelyk: Lightweight Groovy on the Google App Engine
Upcoming SlideShare
Loading in …5
×

Gaelyk: Lightweight Groovy on the Google App Engine

2,759 views
2,696 views

Published on

Gaelyk is a lightweight Groovy web application framework built specifically for the Google App Engine. It provides a fast, easy way to build simply applications in Groovy and host them for free on the GAE.

Published in: Technology, News & Politics
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,759
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

  • On the JDK, we&amp;#x2019;ve got options, and they&amp;#x2019;re growing. Groovy is a better Java focused on strong Java interop, an easy migration path, and easy application coding.
  • Often the Java deployment story is less than happy. The Ops team gets it and feels great about it, but the PHP guys don&amp;#x2019;t know what to do with us. We&amp;#x2019;ve got great framework choices,
  • It should be an easy framework to learn and use.
  • Demo starting up a Gaelyk app.

  • You&amp;#x2019;re running your app on Google&amp;#x2019;s nearly infinitely scalable infrastructure. Go ahead, DDOS it!
  • You&amp;#x2019;re running your app on Google&amp;#x2019;s nearly infinitely scalable infrastructure. Go ahead, DDOS it!
  • You&amp;#x2019;re running your app on Google&amp;#x2019;s nearly infinitely scalable infrastructure. Go ahead, DDOS it!
  • You can sign up and get started and not pay a dime. You get certain free quotas.
  • GAE offers more than just transfer in and out and CPU. All services have their own quotas described at that URL. Since we&amp;#x2019;re talking about Gaelyk, not GAE, we&amp;#x2019;ll move on.
  • If you grow beyond the free quotas, you can always buy more. Internet scale, baby!
  • Started at Python. Now any language of the JVM, within limitations.
  • Started at Python. Now any language of the JVM, within limitations.
  • Started at Python. Now any language of the JVM, within limitations.
  • Started at Python. Now any language of the JVM, within limitations.
  • Started at Python. Now any language of the JVM, within limitations.
  • Started at Python. Now any language of the JVM, within limitations.

  • Remember, it&amp;#x2019;s basically an app server.
  • Remember, it&amp;#x2019;s basically an app server.










  • Remember, it&amp;#x2019;s basically an app server.
  • Most of java.awt, javax.imageio, some java.nio, etc. Performance problems in Java have to do with first-request performance after a delay of no requests.
  • Most of java.awt, javax.imageio, some java.nio, etc. Performance problems in Java have to do with first-request performance after a delay of no requests.
  • Most of java.awt, javax.imageio, some java.nio, etc. Performance problems in Java have to do with first-request performance after a delay of no requests.
  • Most of java.awt, javax.imageio, some java.nio, etc. Performance problems in Java have to do with first-request performance after a delay of no requests.
  • Most of java.awt, javax.imageio, some java.nio, etc. Performance problems in Java have to do with first-request performance after a delay of no requests.
  • Most of java.awt, javax.imageio, some java.nio, etc. Performance problems in Java have to do with first-request performance after a delay of no requests.






  • All examples will be with TextMate and the Console. No Eclipse plugin necessary!













































  • Attachments are optional.
  • Attachments are optional.


























  • A discussion
  • PluginDescriptor can add bindings, etc.
  • PluginDescriptor can add bindings, etc.
  • PluginDescriptor can add bindings, etc.
  • PluginDescriptor can add bindings, etc.
  • PluginDescriptor can add bindings, etc.

  • The GAE SDK contains an embedded Jetty instance that emulates all appropriate services. The Eclipse plugin does this as well, but you don&amp;#x2019;t have to use it.
  • It&amp;#x2019;s also easy to deploy to GAE from the command line.











  • Gaelyk: Lightweight Groovy on the Google App Engine

    1. 1. Lightweight on the by Tim Berglund
    2. 2. Tell me about aGreat Application Language
    3. 3. Tell me a Happy Tale of Deployment
    4. 4. and Make it Fast
    5. 5. Tell me about the Googl eApp Engine
    6. 6. An App Server
    7. 7. In the CLoud
    8. 8. Google Infrastructure
    9. 9. Usually Free!
    10. 10. Quotas http://code.google.com/appengine/docs/quotas.html
    11. 11. Quotas http://code.google.com/appengine/docs/quotas.html
    12. 12. Pricing
    13. 13. Languages
    14. 14. Languages
    15. 15. Languages
    16. 16. Languages
    17. 17. Services
    18. 18. Services It’s an app server
    19. 19. Services With a few extra features
    20. 20. Services
    21. 21. Services Datastore
    22. 22. Services Datastore Authentication
    23. 23. Services Datastore Authentication Caching
    24. 24. Services Datastore Authentication Caching XMPP
    25. 25. Services Datastore Authentication Caching XMPP Email
    26. 26. Services Datastore Task Queue Authentication Caching XMPP Email
    27. 27. Services Datastore Task Queue Authentication Image API Caching XMPP Email
    28. 28. Services Datastore Task Queue Authentication Image API Caching URL Fetching XMPP Email
    29. 29. Services Datastore Task Queue Authentication Image API Caching URL Fetching XMPP OAuth Email
    30. 30. Services Datastore Task Queue Authentication Image API Caching URL Fetching XMPP OAuth Email Blobstore
    31. 31. But It’s not Perfect
    32. 32. Limitations
    33. 33. Limitations The JDK whitelist
    34. 34. Limitations The JDK whitelist http://code.google.com/appengine/docs/java/jrewhitelist.html
    35. 35. Limitations The JDK whitelist http://code.google.com/appengine/docs/java/jrewhitelist.html No Hibernate
    36. 36. Limitations The JDK whitelist http://code.google.com/appengine/docs/java/jrewhitelist.html No Hibernate Only JPA and JDO
    37. 37. Limitations The JDK whitelist http://code.google.com/appengine/docs/java/jrewhitelist.html No Hibernate Only JPA and JDO Grails is limited
    38. 38. Limitations The JDK whitelist http://code.google.com/appengine/docs/java/jrewhitelist.html No Hibernate Only JPA and JDO Grails is limited Performance problems?
    39. 39. Tell me about
    40. 40. Groovy-based
    41. 41. Groovy-based Lightweight
    42. 42. Groovy-based Lightweight Page-centric
    43. 43. Groovy-based Lightweight Page-centric Tightly coupled to the Google App Engine
    44. 44. Groovy-based Lightweight Page-centric Tightly coupled to the Google App Engine A better GAE than the GAE
    45. 45. Setting up Gaelyk
    46. 46. Serving Content
    47. 47. Serving Content
    48. 48. Serving Content Static content (like in a WAR)
    49. 49. Serving Content Static content (like in a WAR) Groovy templates
    50. 50. Templates <% include '/WEB-INF/includes/header.gtpl' %> <h1>Look Up an Artist</h1> <form action="/artistLookup.groovy" method="POST"> <input type="text" size="50" name="artist"/> <input type="submit" value="Lookup"/> </form> <ul> <% request.artists.each { artist -> %> <li>${artist.name}</li> <% } %> </ul> <% include '/WEB-INF/includes/footer.gtpl' %>
    51. 51. Templates <% include '/WEB-INF/includes/header.gtpl' %> <h1>Look Up an Artist</h1> <form action="/artistLookup.groovy" method="POST"> <input type="text" size="50" name="artist"/> <input type="submit" value="Lookup"/> </form> <ul> <% request.artists.each { artist -> %> <li>${artist.name}</li> <% } %> </ul> <% include '/WEB-INF/includes/footer.gtpl' %>
    52. 52. Templates <% include '/WEB-INF/includes/header.gtpl' %> <h1>Look Up an Artist</h1> <form action="/artistLookup.groovy" method="POST"> <input type="text" size="50" name="artist"/> <input type="submit" value="Lookup"/> </form> <ul> <% request.artists.each { artist -> %> <li>${artist.name}</li> <% } %> </ul> <% include '/WEB-INF/includes/footer.gtpl' %>
    53. 53. Templates <% include '/WEB-INF/includes/header.gtpl' %> <h1>Look Up an Artist</h1> <form action="/artistLookup.groovy" method="POST"> <input type="text" size="50" name="artist"/> <input type="submit" value="Lookup"/> </form> <ul> <% request.artists.each { artist -> %> <li>${artist.name}</li> <% } %> </ul> <% include '/WEB-INF/includes/footer.gtpl' %>
    54. 54. Templates <% include '/WEB-INF/includes/header.gtpl' %> <h1>Look Up an Artist</h1> <form action="/artistLookup.groovy" method="POST"> <input type="text" size="50" name="artist"/> <input type="submit" value="Lookup"/> </form> <ul> <% request.artists.each { artist -> %> <li>${artist.name}</li> <% } %> </ul> <% include '/WEB-INF/includes/footer.gtpl' %>
    55. 55. Templates
    56. 56. Templates Lightweight, Groovy JSPs
    57. 57. Templates Lightweight, Groovy JSPs Downside: Scriptlets
    58. 58. Templates Lightweight, Groovy JSPs Downside: Scriptlets Request attributes bound from Groovlets
    59. 59. Groovlets import java.net.URLEncoder if(params.artist) { def response = urlFetch.fetch(new URL("http://musicbrainz.org/ ws/1/artist/?type=xml&name=${URLEncoder.encode(params.artist)}")) def text = new String(response.content) def xml = new XmlSlurper().parseText(text) request.artists = xml.'artist-list'.artist } else { request.artists = [] } forward '/artistLookup.gtpl'
    60. 60. Groovlets
    61. 61. Groovlets Groovy script, meet Servlet
    62. 62. Groovlets Groovy script, meet Servlet Intrinsic variables
    63. 63. Groovlets Groovy script, meet Servlet Intrinsic variables Forwarding
    64. 64. Groovlets Groovy script, meet Servlet Intrinsic variables Forwarding Redirecting
    65. 65. Groovlets Groovy script, meet Servlet Intrinsic variables Forwarding Redirecting MarkupBuilder
    66. 66. import java.net.URLEncoder if(params.artist) { def response = urlFetch.fetch(new URL("http:// musicbrainz.org/ws/1/artist/?type=xml&name=$ {URLEncoder.encode(params.artist)}")) def text = new String(response.content) def xml = new XmlSlurper().parseText(text) request.artists = xml.'artist-list'.artist } else { request.artists = [] } forward '/artistLookup.gtpl'
    67. 67. import java.net.URLEncoder if(params.artist) { def response = urlFetch.fetch(new URL("http:// musicbrainz.org/ws/1/artist/?type=xml&name=$ {URLEncoder.encode(params.artist)}")) def text = new String(response.content) def xml = new XmlSlurper().parseText(text) request.artists = xml.'artist-list'.artist } else { request.artists = [] } forward '/artistLookup.gtpl'
    68. 68. import java.net.URLEncoder if(params.artist) { def response = urlFetch.fetch(new URL("http:// musicbrainz.org/ws/1/artist/?type=xml&name=$ {URLEncoder.encode(params.artist)}")) def text = new String(response.content) def xml = new XmlSlurper().parseText(text) request.artists = xml.'artist-list'.artist } else { request.artists = [] } forward '/artistLookup.gtpl'
    69. 69. import java.net.URLEncoder if(params.artist) { def response = urlFetch.fetch(new URL("http:// musicbrainz.org/ws/1/artist/?type=xml&name=$ {URLEncoder.encode(params.artist)}")) def text = new String(response.content) def xml = new XmlSlurper().parseText(text) request.artists = xml.'artist-list'.artist } else { request.artists = [] } forward '/artistLookup.gtpl'
    70. 70. import com.google.appengine.api.datastore.* import static com.google.appengine.api.datastore.FetchOption if(!user) { redirect users.createLoginURL(request.requestURL.toString( return } def query = new Query("project") query.addSort("dateCreated", Query.SortDirection.ASCENDING) PreparedQuery preparedQuery = datastore.prepare(query) request.projects = preparedQuery.asList( withOffset(0) ) forward "/WEB-INF/views/project/list.gtpl"
    71. 71. import com.google.appengine.api.datastore.* import static com.google.appengine.api.datastore.FetchOption if(!user) { redirect users.createLoginURL(request.requestURL.toString( return } def query = new Query("project") query.addSort("dateCreated", Query.SortDirection.ASCENDING) PreparedQuery preparedQuery = datastore.prepare(query) request.projects = preparedQuery.asList( withOffset(0) ) forward "/WEB-INF/views/project/list.gtpl"
    72. 72. import com.google.appengine.api.datastore.* import static com.google.appengine.api.datastore.FetchOption if(!user) { redirect users.createLoginURL(request.requestURL.toString( return } def query = new Query("project") query.addSort("dateCreated", Query.SortDirection.ASCENDING) PreparedQuery preparedQuery = datastore.prepare(query) request.projects = preparedQuery.asList( withOffset(0) ) forward "/WEB-INF/views/project/list.gtpl"
    73. 73. import com.google.appengine.api.datastore.* import static com.google.appengine.api.datastore.FetchOption if(!user) { redirect users.createLoginURL(request.requestURL.toString( return } def query = new Query("project") query.addSort("dateCreated", Query.SortDirection.ASCENDING) PreparedQuery preparedQuery = datastore.prepare(query) request.projects = preparedQuery.asList( withOffset(0) ) forward "/WEB-INF/views/project/list.gtpl"
    74. 74. import com.google.appengine.api.datastore.* import static com.google.appengine.api.datastore.FetchOption if(!user) { redirect users.createLoginURL(request.requestURL.toString( return } def query = new Query("project") query.addSort("dateCreated", Query.SortDirection.ASCENDING) PreparedQuery preparedQuery = datastore.prepare(query) request.projects = preparedQuery.asList( withOffset(0) ) forward "/WEB-INF/views/project/list.gtpl"
    75. 75. import com.google.appengine.api.datastore.* import static com.google.appengine.api.datastore.FetchOption if(!user) { redirect users.createLoginURL(request.requestURL.toString( return } def query = new Query("project") query.addSort("dateCreated", Query.SortDirection.ASCENDING) PreparedQuery preparedQuery = datastore.prepare(query) request.projects = preparedQuery.asList( withOffset(0) ) forward "/WEB-INF/views/project/list.gtpl"
    76. 76. URL Mapping
    77. 77. URL Mapping Templates in war/*.gtpl
    78. 78. URL Mapping Templates in war/*.gtpl Groovlets in war/WEB-INF/groovy/*.groovy
    79. 79. URL Mapping Templates in war/*.gtpl Groovlets in war/WEB-INF/groovy/*.groovy Pretty URLs with war/WEB-INF/routes.groovy
    80. 80. The Datastore
    81. 81. The Datastore
    82. 82. The Datastore Google’s BigTable infrastructure
    83. 83. The Datastore Google’s BigTable infrastructure Schemaless
    84. 84. The Datastore Google’s BigTable infrastructure Schemaless Named entities (property bundles)
    85. 85. The Datastore Google’s BigTable infrastructure Schemaless Named entities (property bundles) Indexed, queryable, sortable
    86. 86. The Datastore Google’s BigTable infrastructure Schemaless Named entities (property bundles) Indexed, queryable, sortable Transactional
    87. 87. The Datastore Google’s BigTable infrastructure Schemaless Named entities (property bundles) Indexed, queryable, sortable Transactional Great Groovy wrapper
    88. 88. Datastore Indexes
    89. 89. Datastore Indexes Automatically generated by default
    90. 90. Datastore Indexes Automatically generated by default Override in WEB-INF/datastore-indexes.xml
    91. 91. Datastore Indexes Automatically generated by default Override in WEB-INF/datastore-indexes.xml <?xml version="1.0" encoding="utf-8"?> <datastore-indexes   autoGenerate="true">     <datastore-index kind="Employee" ancestor="false">         <property name="lastName" direction="asc" />         <property name="hireDate" direction="desc" />     </datastore-index>     <datastore-index kind="Project" ancestor="false">         <property name="dueDate" direction="asc" />     </datastore-index> </datastore-indexes>
    92. 92. Tell me about Other Services
    93. 93. Email in Java
    94. 94. Email with Gaelyk mail.send sender: 'story-admin@augusttechgroup.com', to: 'tlberglund@gmail.com', subject: 'Story Complete', textBody: "A story you edited has increased in priority. Check it out."
    95. 95. Inbound Email
    96. 96. Inbound Email Enable in appengine-web.xml
    97. 97. Inbound Email Enable in appengine-web.xml Enable built-in servlet in web.xml
    98. 98. Inbound Email Enable in appengine-web.xml Enable built-in servlet in web.xml email.groovy Groovlet
    99. 99. Inbound Email Enable in appengine-web.xml Enable built-in servlet in web.xml email.groovy Groovlet The “message” intrinsic variable
    100. 100. Memcache in Java
    101. 101. Memcache with Gaelyk def countryFr = new Country(name: 'France') memcache['FR'] = countryFr if ('FR' in memcache) { countryFromCache = memcache['FR'] }
    102. 102. URL Fetch in Java
    103. 103. URL Fetch with Gaelyk def response = urlFetch.fetch(new URL("http://example.com")) def text = new String(response.content)
    104. 104. Task Queues queue.add countdownMillis: 10000, url: '/task/emailTaskList', taskName: 'Email current story assignments', method: 'PUT', params: [date: new Date()]
    105. 105. Task Queues
    106. 106. Task Queues Timed HTTP requests
    107. 107. Task Queues Timed HTTP requests Configure in war/WEB-INF/queue.xml
    108. 108. Task Queues Timed HTTP requests Configure in war/WEB-INF/queue.xml http://code.google.com/appengine/docs/java/config/queue.html
    109. 109. Task Queues Timed HTTP requests Configure in war/WEB-INF/queue.xml http://code.google.com/appengine/docs/java/config/queue.html Can update without redeploying
    110. 110. Task Queues Timed HTTP requests Configure in war/WEB-INF/queue.xml http://code.google.com/appengine/docs/java/config/queue.html Can update without redeploying Can be secured
    111. 111. XMPP
    112. 112. XMPP User notification
    113. 113. XMPP User notification XML payloads for distributed communication
    114. 114. XMPP User notification XML payloads for distributed communication Send messages with a Groovier API
    115. 115. XMPP User notification XML payloads for distributed communication Send messages with a Groovier API Receive messages through a servlet
    116. 116. XMPP Sending in Java
    117. 117. XMPP Sending with Gaelyk
    118. 118. XMPP Sending with Gaelyk def recipient = 'tlberglund@gmail.com' if (xmpp.getPresence(recipient).isAvailable()) { def status = xmpp.send(to: recipient, body: "Glad you're into Gaelyk!") if (!status.isSuccessful()) {
    119. 119. XMPP Sending with Gaelyk def recipient = 'tlberglund@gmail.com' if (xmpp.getPresence(recipient).isAvailable()) { def status = xmpp.send(to: recipient, body: "Glad you're into Gaelyk!") if (!status.isSuccessful()) { // ...
    120. 120. XMPP Sending with Gaelyk def recipient = 'tlberglund@gmail.com' if (xmpp.getPresence(recipient).isAvailable()) { def status = xmpp.send(to: recipient, body: "Glad you're into Gaelyk!") if (!status.isSuccessful()) { // ... } }
    121. 121. XMPP Receiving
    122. 122. XMPP Receiving Enable in appengine-web.xml
    123. 123. XMPP Receiving Enable in appengine-web.xml Enable built-in servlet in web.xml
    124. 124. XMPP Receiving Enable in appengine-web.xml Enable built-in servlet in web.xml /war/WEB-INF/groovy/jabber.groovy
    125. 125. XMPP Receiving Enable in appengine-web.xml Enable built-in servlet in web.xml /war/WEB-INF/groovy/jabber.groovy The “message” intrinsic variable
    126. 126. Plugins
    127. 127. Plugins
    128. 128. Plugins Analogous to Grails plugins
    129. 129. Plugins Analogous to Grails plugins Mini Gaelyk apps
    130. 130. Plugins Analogous to Grails plugins Mini Gaelyk apps plugins/xxxPluginDescriptor.groovy
    131. 131. Plugins Analogous to Grails plugins Mini Gaelyk apps plugins/xxxPluginDescriptor.groovy Bundled as ZIP files
    132. 132. Plugins Analogous to Grails plugins Mini Gaelyk apps plugins/xxxPluginDescriptor.groovy Bundled as ZIP files Ad-hoc discovery and distribution
    133. 133. Development
    134. 134. What about Services in development?
    135. 135. GAE Emulation
    136. 136. GAE Emulation Datastore simulated in filesystem
    137. 137. GAE Emulation Datastore simulated in filesystem General Administration
    138. 138. GAE Emulation Datastore simulated in filesystem General Administration http://localhost:8080/_ah/admin
    139. 139. GAE Emulation Datastore simulated in filesystem General Administration http://localhost:8080/_ah/admin Authentication
    140. 140. GAE Emulation Datastore simulated in filesystem General Administration http://localhost:8080/_ah/admin Authentication http://localhost:8080/_ah/login
    141. 141. GAE Emulation Datastore simulated in filesystem General Administration http://localhost:8080/_ah/admin Authentication http://localhost:8080/_ah/login http://localhost:8080/_ah/logout
    142. 142. Code
    143. 143. On github git@github.com:tlberglund/august-stories.git git@github.com:tlberglund/august-demo.git
    144. 144. Thank You Tim Berglund www.augusttechgroup.com tim.berglund@augusttechgroup.com @tlberglund Using Your Existing Team
    145. 145. Photo Credits Parchment Background http://www.photoshopstar.com/effects/recreate-indiana-jones-text-effect/

    ×