<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Google App Engine</title>
    <description>关于Google App Engine的技术圈</description>
    <link>http://gae.group.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>在GAE中生成全局序列号</title>
        <author>pickerel</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://pickerel.javaeye.com">pickerel</a>&nbsp;
          链接：<a href="http://gae.group.javaeye.com/group/blog/182755" style="color:red;">http://gae.group.javaeye.com/group/blog/182755</a>&nbsp;
          发表时间: 2008年04月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          gae不能写文件，所以很多操作只能用datastore来实现了。<br /><br /><pre name="code" class="python">
class Sequence(db.Model):
    @staticmethod
    def next():
        seq = Sequence()       
        seq.put()
        id = seq.key().id()
        seq.delete()
        return id    
</pre><br /><br />使用<br /><pre name="code" class="python">print Sequence.next()</pre>
          <br/>
          <span style="color:red;">
            <a href="http://gae.group.javaeye.com/group/blog/182755#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 15 Apr 2008 02:08:13 +0800</pubDate>
        <link>http://gae.group.javaeye.com/group/blog/182755</link>
        <guid>http://gae.group.javaeye.com/group/blog/182755</guid>
      </item>
      <item>
        <title>Restful your google app engine applications</title>
        <author>pickerel</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://pickerel.javaeye.com">pickerel</a>&nbsp;
          链接：<a href="http://gae.group.javaeye.com/group/blog/182754" style="color:red;">http://gae.group.javaeye.com/group/blog/182754</a>&nbsp;
          发表时间: 2008年04月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          使用示例：<br /><pre name="code" class="python">#author:pickerel@gmail.com
import wsgiref.handlers
from google.appengine.ext import webapp
from rest import *

    
class CommentResource(RestResource):
    def initialize(self):
        self.response.out.write("comment.initialize:format=%s&lt;br/>" %(self.format))
    def index(self, entry_id):
        self.response.out.write("comment.index:entry_id=%s&lt;br/>" % entry_id)
    def show(self, id, entry_id):
        self.response.out.write("comment.show:id=%s,entry_id=%s&lt;br/>" %(id, entry_id))        
    def create(self, entry_id):
        self.response.out.write("comment.show:id=%s,entry_id=%s&lt;br/>" %(id, entry_id))        
    def update(self, id, entry_id):
        self.response.out.write("comment.update:id=%s,entry_id=%s&lt;br/>" %(id, entry_id))        
    def delete(self, id, entry_id):
        self.response.out.write("comment.delete:id=%s,entry_id=%s&lt;br/>" %(id, entry_id))        
        
class EntryResource(RestResource):
    def initialize(self):
        self.response.out.write("entry.initialize:format=%s&lt;br/>" %(self.format))
    def index(self):
        self.response.out.write("entry.index&lt;br/>")
    def show(self, id):
        self.response.out.write("entry.show:id=%s&lt;br/>" %(id))        
    def create(self):
        self.response.out.write("entry.show:id=%s&lt;br/>" %(id))        
    def update(self, id):
        self.response.out.write("entry.update:id=%s&lt;br/>" %(id))        
    def delete(self, id):
        self.response.out.write("entry.delete:id=%s&lt;br/>" %(id))   
        """"""
        
def main():
  RestHandler.route = {
           '/entries' : EntryResource,
           '/entries/:entry_id/comments' : CommentResource}
  
  application = webapp.WSGIApplication([(".*", RestHandler)],     debug=True)
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()
</pre><br /><br />在这个rest实现机制中，资源支持的操作有5种,index,show,create,update,delete。<br />请求会根据请求的http method和路由设定自动和资源绑定。<br />比如<br />'/entries/:entry_id/comments' : CommentResource<br />这个路由说明 /entries/:entry_id/comments　这个模式的url将绑定到CommentResource上，<br />其中:entry_id是一个参数。<br />配置这个路由后，访问<br />/entries/2/comments 将调用CommentResource的index(self, entry_id)方法，里面的entry_id与路由配置的:entry_id是对应的，这里entry_id=2<br />同样<br />/entries/2/comments/1 将调用CommentResource的show(self, id, entry_id)方法，调用时候id=1,entry_id=2<br /><br />该实现还支持不同的内容格式请求的区分，<br />/entries/2/comments/1<br />/entries/2/comments/1.html<br />/entries/2/comments/1.xml<br />这三个请求都将调用CommentResource的show(self, id, entry_id)方法，在这个方法中，可以通过self.format来获取用户所请求的格式，上面三个请求的内容格式分别为 html, html, xml<br /><br />文件rest.py，实现url的解析及和资源的绑定<br /><pre name="code" class="python">#author:pickerel@gmail.com
import wsgiref.handlers
from google.appengine.ext import webapp

_DEFAUT_RESOURCE_FORMAT = 'html'
class RestResource:
    def __init__(self, request, response, params = {}, value = None, format = _DEFAUT_RESOURCE_FORMAT):
        self.request = request
        self.response = response
        self.params = params
        self.value = value
        self.format = format
        
    def initialize(self):
        """"""
    def index(self, *args):
        """"""
    def show(self, res, *args):
        """"""        
    def create(self, *args):
        """"""
    def update(self, res, *args):
        """"""
    def delete(self, res, *args):
        """"""
        
class RestHandler(webapp.RequestHandler):
    route = {}
    #{
    #         '/':IndexResource,
    #         '/entries' : EntryResource,
    #         '/entries/:entry_id/comments' : CommentResource}
      
    def __init__(self):
      self.resource = None
    
    def initialize(self, request, response):
      webapp.RequestHandler.initialize(self, request, response)
      if self.request.path == '' or self.request.path == '/':        
          self.resource = RestHandler.route['/'](request, response)
      else:
          self.resource = RestHandler.get_rest_resource(request, response)
          
      if self.resource != None:
          self.resource.initialize()
      else:
          self.error(404)
          
    @staticmethod
    def get_rest_resource(request, response):
      path_fields = request.path[1:].split("/")
      resource = None
      resource_paramters = {}
      resource_value = None
      resource_format = _DEFAUT_RESOURCE_FORMAT
      
      for item in RestHandler.route.items():
          resource = None
          resource_value = None
          resource_paramters.clear()
          resource_format = _DEFAUT_RESOURCE_FORMAT
          
          route_path = item[0][1:]
          route_path_fields = route_path.split("/")
          if len(route_path_fields) == len(path_fields) or len(route_path_fields) + 1 == len(path_fields):
              resource = item[1]
              for i in range(len(path_fields)):
                  if i == len(path_fields) - 1 and path_fields[i].find(".") != -1:
                      arr = path_fields[i].split('.')
                      path_fields[i] = arr[0]
                      resource_format = arr[1]
                  if i  == len(route_path_fields):
                      resource_value = path_fields[i]
                  elif path_fields[i] == route_path_fields[i]:
                      continue
                  elif route_path_fields[i].startswith(":"):
                      resource_paramters[route_path_fields[i][1:]] = path_fields[i]
                  else:
                      resource = None
                      break
                  
          if resource != None:
              break;
         
      if resource == None:
          return None
      else:
          return resource(request, response, resource_paramters, resource_value, resource_format)

    def get(self):
      if self.resource != None:
        if self.resource.value != None:
            self.resource.show(self.resource.value, **self.resource.params)
        else:
            self.resource.index( **self.resource.params)
    
    def post(self):
      """Handler method for POST requests."""
      if self.resource != None:
        if self.resource.value != None:
           self.resource.create( **self.resource.params)
        else:
           self.error(404)           
    
    def put(self):
      if self.resource != None:
        if self.resource.value != None:
            self.resource.update(self.resource.vaue, **self.resource.params)
        else:
            self.error(404)
            
    def delete(self):
      if self.resource != None:
        if self.resource.value != None:
            self.resource.delete(self.resource.vaue, **self.resource.params)
        else:
            self.error(404)</pre><br /><br /><br /><br />完整代码见附件
          <br/>
          <span style="color:red;">
            <a href="http://gae.group.javaeye.com/group/blog/182754#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 15 Apr 2008 01:47:40 +0800</pubDate>
        <link>http://gae.group.javaeye.com/group/blog/182754</link>
        <guid>http://gae.group.javaeye.com/group/blog/182754</guid>
      </item>
      <item>
        <title>在GAE中使用django模板</title>
        <author>pickerel</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://pickerel.javaeye.com">pickerel</a>&nbsp;
          链接：<a href="http://gae.group.javaeye.com/group/blog/181969" style="color:red;">http://gae.group.javaeye.com/group/blog/181969</a>&nbsp;
          发表时间: 2008年04月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Google App Engine自带了django框架，开发者可以直接在上面使用django开始web程序，如果你不打算去学django框架，而只是想用它的模板机制，那也是可以的，这里以一个hello, world为例做个演示：<br /><br />文件：./simple_blog/app.yaml<br />application: simple-blog<br />version: 1<br />runtime: python<br />api_version: 1<br /><br />handlers:<br />- url: /.*<br />  script: simple_blog.py<br /><br />文件：./simple_blog/simple_blog.py<br /><pre name="code" class="python">#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cgi
import sys, os
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template

_DEBUG = True

class BaseRequestHandler(webapp.RequestHandler):
  """套用模板"""
  def render(self, template_name, template_values={}):
    values = {
      'request': self.request,
      'application_name': 'test',
    }
    values.update(template_values)
    directory = os.path.dirname(__file__)
    #指定模板文件路径
    path = os.path.join(directory, os.path.join('templates', template_name))
    self.response.out.write(template.render(path, values, debug=_DEBUG))
 
class IndexPage(BaseRequestHandler):
  def get(self):
    self.render('index.html', {
      'title': 'Index',
      'content': 'Hello, World'
    })

#配置URL路由
application = webapp.WSGIApplication([
  ('/', IndexPage)
], debug=_DEBUG)


def main():
  wsgiref.handlers.CGIHandler().run(application)
 
if __name__ == '__main__':
  main() </pre><br /><br />文件：./simple_blog/templates/index.html<br /><pre name="code" class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
&lt;html xmlns="http://www.w3.org/1999/xhtml">
  &lt;head>
    &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    &lt;title>{{application_name }} - {{title}}&lt;/title>
  &lt;/head>
  &lt;body>
    {{content}}
  &lt;/body>
&lt;/html></pre><br /><br />附件是一个完整的google app engine演示例子，关于django模板的更详细的说明请参见<br /><a href="http://www.woodpecker.org.cn/obp/django/django-faq/templates.html" target="_blank">http://www.woodpecker.org.cn/obp/django/django-faq/templates.html</a>
          <br/>
          <span style="color:red;">
            <a href="http://gae.group.javaeye.com/group/blog/181969#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 11 Apr 2008 23:07:02 +0800</pubDate>
        <link>http://gae.group.javaeye.com/group/blog/181969</link>
        <guid>http://gae.group.javaeye.com/group/blog/181969</guid>
      </item>
      <item>
        <title>在GAE中读取yaml的例子</title>
        <author>pickerel</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://pickerel.javaeye.com">pickerel</a>&nbsp;
          链接：<a href="http://gae.group.javaeye.com/group/blog/181964" style="color:red;">http://gae.group.javaeye.com/group/blog/181964</a>&nbsp;
          发表时间: 2008年04月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在Google App Engine中内置了yaml文件的验证、解析方法，下面演示一个在GAE中读取yaml的例子<br /><br />待读取的配置文件 config.yaml 内容如下：<br />blog_name: 我们的博客<br />allow_comment: False<br />masters:<br />- name: Pickerel Yee<br />  account: pickerel@gmail.com<br /><br />- name: 王二<br />  account: wang2@gmail.com<br /><br />建立配置验证读取文件 config.py<br /><pre name="code" class="python">#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
from google.appengine.api import validation
from google.appengine.api import yaml_listener
from google.appengine.api import yaml_builder
from google.appengine.api import yaml_object
from simple_blog import *
class BlogMaster(validation.Validated):
  ATTRIBUTES = {
    'name': validation.TYPE_UNICODE,
    'account': r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$'
  }
class ConfigExternal(validation.Validated):
  ATTRIBUTES = {
    'blog_name': validation.TYPE_UNICODE, 
    'allow_comment': validation.Type(bool, default=False),
    'masters': validation.Optional(validation.Repeated(BlogMaster))
  }

#配置类
class Config(object): # subclassing from object for 2.2, unnecessary after that
  instance = None
  def __init__(self):
    self.blog_name = 'blog'
    self.blog_masters = []
    self.allow_comment = True       
  
  @staticmethod
  def get_instance():
    if Config.instance == None:
      Config.instance = Config.load()
    return Config.instance
  
  @staticmethod
  def load():
    """parses the config.yaml file"""
    _BASE_PATH = os.path.abspath(os.path.dirname(__file__))
    config_file = os.path.join(_BASE_PATH, "config.yaml")
    fh = open(config_file, "r")
    try:
      builder = yaml_object.ObjectBuilder(ConfigExternal)
      handler = yaml_builder.BuilderHandler(builder)
      listener = yaml_listener.EventListener(handler)
      listener.Parse(fh)      
      return handler.GetResults()[0]
    finally:
      fh.close()

</pre><br />GAE中内置了基本数据类型的验证方法，更复杂的验证可以通过正则式或者自定义验证方法来实现。<br /><br />使用<br /><pre name="code" class="python">print config.get_instance().blog_name</pre><br /><br />附件是一个完整的演示例子。
          <br/>
          <span style="color:red;">
            <a href="http://gae.group.javaeye.com/group/blog/181964#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 11 Apr 2008 22:53:32 +0800</pubDate>
        <link>http://gae.group.javaeye.com/group/blog/181964</link>
        <guid>http://gae.group.javaeye.com/group/blog/181964</guid>
      </item>
      <item>
        <title>bug in gae:regex invalid: unbalanced parenthesis</title>
        <author>pickerel</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://pickerel.javaeye.com">pickerel</a>&nbsp;
          链接：<a href="http://gae.group.javaeye.com/group/blog/180717" style="color:red;">http://gae.group.javaeye.com/group/blog/180717</a>&nbsp;
          发表时间: 2008年04月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在windows下运行一个示例工程的时候返回错误 <br /><span style="color: red">regex invalid: unbalanced parenthesis</span><br /><br />修正：<br />找到 google\appengine\tools\dev_appserver.py 文件，到2369行把以下两行代码<br /><pre name="code" class="python">      regex = os.path.join(re.escape(regex), '(.*)')
      path = os.path.join(path, '\\1')</pre><br /><br />修改为<br /><pre name="code" class="python">
      regex = re.escape(regex) + '/(.*)'
      path = path + '/\\1'</pre><br /><br />在1.0.1版的sdk中已经解决了这个问题。
          <br/>
          <span style="color:red;">
            <a href="http://gae.group.javaeye.com/group/blog/180717#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 09 Apr 2008 10:24:59 +0800</pubDate>
        <link>http://gae.group.javaeye.com/group/blog/180717</link>
        <guid>http://gae.group.javaeye.com/group/blog/180717</guid>
      </item>
  </channel>
</rss>