扩展EGL支持Google App Engine Datastore数据存储

1 简介

建议:读者在开始做对Google App Engine的扩展之前,需要了解和具备以下的基础知识:
  • EGL以及EDT的知识
  • Google App Engine的数据存储(Data Store)部分
  • Eclipse插件开发的知识和经验
  • Java EE的基础知识


    EGL作为一门业务语言,提供了一套抽象的面向业务开发的语言模型。EGL程序员能利用这套面向业务的语言模型方便、快捷地开发出跨平台的、跨语言的各种业务系统。EGL针对业务系统里经常用到的数据访问操作定义了一系列语句,比如,

  • get:从某数据源里取得数据
  • add:往某数据源插入数据
  • replace:向某数据源更新数据
  • delete:从某数据源删除数据
     这些EGL提供的抽象的数据访问的操作语句,可以进行扩展。如下图所示,这些抽象的数据存取操作可以是EGL现在已经支持的基于Java JDBC关系数据库的实现,也可以是基于Java的文件系统的实现,或者是.net C#的ODBC实现等,甚至是Google App Engine提供的Datastore数据存取实现。


GoogleApp Engine提供了一种不同于关系型数据库的数据存储,基于BigTable的Datastore。通过把EGL数据操作语句扩展到Datastore,EGL使用者可以在不了解Datastore技术细节的情况下轻易写出能够利用Datastore存储的应用程序。甚至可以几乎不做改动的将一个使用SQL存储的程序切换成使用Datastore存储。由此意味着EGL程序员在不改变应用程序的前提下,通过扩展EGL,能毫不费劲地把一个基于Java JDBC关系数据库实现的应用无缝的迁移到任何新出现的平台上(包括我们即将要实现的扩展GAE BigTable DataStore),这样能大大提高应用程序的开发效率和降低开发成本。

    这篇blog介绍如何扩展EGL中的add语句来调用GAE的存储API,带领大家一起来学习EGL是如何在语言模型、代码生成器上进行扩展的。


2. 开发目标

     本文的目标是扩展EGL,用于实现和Google App Engine数据存储的集成。我们展示了如何用EGL语言来实现向GoogleApp Engine数据存储中插入实体数据的过程,并给出一个包括EGL Rich UI和EGL REST Service的样例,最终将该样例部署到Google App Engine上。

3. 扩展过程概述

    这里先大概介绍一下进行EGL扩展的策略。

    第一,需要先掌握目标扩展平台的相关知识;

    第二,参考现有的EGL语言模型,看是否能够适应要扩展的目标平台;

    第三,手工先实现一下将要被生成的目标平台的代码,为实现自己的代码生成器做准备;

    第四,总结目标生成代码,决定是否有必要提炼出一个目标平台的运行时,以方便代码生成。

3.1和3.2简单概述了扩展EGL的步骤,具体的细节,请参考章节4、5和6。

3.1 模型扩展

    通常,针对数据模型的存取,EGL会提供一个数据源(DataSource)作为数据存取和访问的入口点。如针对关系数据库,用户可以使用SQLDataSource来进行数据的增、删、改、查。

    同样,如果需要向GoogleApp Engine的数据存储(Data Store)进行数据的存取和访问等操作,也需要一个数据源,这就需要我们对已有的EGL模型进行扩展。以下是扩展的一个简单流程:

  • 创建Google App Engine的数据存储的数据源GAEDataSource。
  • 定义和Google App Engine的数据存储相关的EGL模型。
  •  向EGL编译器注册自定义的EGL模型。

3.2 代码生成器扩展

   在扩展完GAEDataSource和相应的EGL模型后,还需要对代码生成器(EGL Generator)进行扩展,从而生成相应的和Google App Engine相集成的Java代码。

   基于Java的代码生成器的扩展,一般有两种方式:

  • 创建新的代码生成器。一般是创建新的代码生成器如GAEGenerator、相应的模板以及模板的描述文件templates.properties,并且需要对界面作一些扩展。
  • 扩展已有的代码生成器。这种情况相对简单,一般只需创建新的模板以及模板描述文件templates.properties即可。

   在本文中,我们采用第二种方式。关于如何扩展代码生成器,读者可以参考DW中国上的EGL系列文章的第四篇来了解更多详细信息【待定】。

4. 设置开发环境

4.1 装GAE插件

    关于如何安装和配置GAE插件,读者可以访问Google App Engine的官方文档https://developers.google.com/appengine/downloads#Download_the_Google_Plugin_for_Eclipse去自行安装和设置。

4.2 安装设置EDT开发环境

    关于如何安装EDT以及配置EDT等具体的技术细节,读者可以参考在线帮助文档“EGL语言从入门到精通:http://blog.csdn.net/rationalgroup/article/details/7336753”。

4.3 设置开发工作空间

    在安装和配置完GAE和EDT插件后,读者需要从Eclipse的CVS上检出EDT相关的源代码。具体步骤如下:

  • 切换到CVS Repository Exploring透视图下
  • 增加一个CVS Repository: pserver:anonymous@dev.eclipse.org:/cvsroot/tools
  • 在CVS Repositories视图中,导航到EDT的目录下,如图所示:

检出所需要的插件项目。在这里读者需要注意的是应该检出每个项目的EDT080GM版本,如图所示:






  • 用以上方法检出所需要的以下插件项目(当然读者也可以将org.eclipse.edt下所有插件项目都检出到工作空间中):
    • org.eclipse.edt.compiler
    • org.eclipse.edt.ide.compiler
    • org.eclipse.edt.mof.egl
    • org.eclipse.edt.runtime.java

5. 模型扩展

5.1 创建GAEDataSource外部类型

Google App Engine的数据储存代表一个新的数据源,因此在这里我们需要创建一个新的EGL版型GAEDataSource来表示它。

在插件org.eclipse.edt.compiler中新建一个EGL包eglx.gae,并创建一个外部类型(ExternalType)。这个外部类型用于定义一个DataSource,用于和其他DataSource进行区分。

externalType GAEDataSource extends DataSource type NativeType  
end


GAEDataSource的程序目录结构

创建完外部类型以后,需要运行tools/build-CompilerEGLAR.xml的ANT脚本来在lib目录下编译生成相应的EGLAR文件edtCompiler.eglar。

接下来需要在插件org.eclipse.edt.runtime.java中添加一个空实现的Java类eglx.gae.GAEDataSource.java。具体的程序结构读者可以自行参考附件中的样例程序【

http://download.csdn.net/detail/rationalgroup/4326397   】。

5.2 扩展EGL Model

在创建完GAEDataSource以后,需要扩展相应的EGL Model来标识和Google AppEngine数据储存相关的模型。在本文中,我们仅给出add语句的样例,读者可以参考这个实现来实现其他的抽象语句(如get, replace, delete)。

首先在EDT中创建一个插件项目org.eclipse.edt.mof.eglx.gae,右击该项目,在右键菜单中选择Configure -> Convert to EGL Project,这样该项目就转换成一个EGL插件项目。

在该项目中创建一个EGL源文件GAEActionStatement.egl:


externalType GAEActionStatement extends IOStatement type MofClass  
end  
  
externalType GAEAddStatement extends GAEActionStatement, AddStatement type  MofClass  
end  
同时需要在该插件中创建与以上所定义的EGL Model相对应的Java类(参考样例程序【
http://download.csdn.net/detail/rationalgroup/4326397 
】),这个插件的目录结构如图所示:


org.eclipse.edt.mof.eglx.gae插件

运行tools/build-MofEglMOFAR.xml生成egllib下面的mofar和eglar包:gae.eglar和gae.mofar(读者可以拷贝样例程序中的Ant脚本到该项目中)。

这个插件的作用类似于源代码中的org.eclipse.edt.mof.eglx.services插件,具体的Java接口和实现读者可以参考这个插件。

5.3 注册扩展EGL模型

    创建完EGL Model以后,我们需要在EGL的Compiler插件org.eclipse.edt.compiler注册这些模型,使得Compiler可以识别这些新定义的EGL Model。

  • 在插件org.eclipse.edt.compiler添加类org.eclipse.edt.compiler.internal.egl2mof.eglx.gae.GAEActionStatementGenerator。这个类作用类似于org.eclipse.edt.compiler.internal.egl2mof.eglx.services.ServicesActionStatementGenerator用来把新定义的外部类型和EGL compiler链接在一起。具体的源码读者可以参考附件中的样例程序
    http://download.csdn.net/detail/rationalgroup/4326397  。
  • 把类GAEActionStatement注册到类org.eclipse.edt.compiler.EDTCompiler。加入
  •  path +=SystemEnvironmentUtil.getSystemLibraryPath(GAEActionStatement.class,"egllib");
  • 把插件org.eclipse.edt.mof.eglx.gae 注册到类org.eclipse.edt.ide.compiler.IDEEDTCompiler。加入
  •  path +=getPathToPluginDirectory("org.eclipse.edt.mof.eglx.gae","egllib");
  • 把类GAEActionStatementGenerator注册到类org.eclipse.edt.compiler.internal.egl2mof.Egl2MofStatement。加入
  • IOStatementGenerator.Registry.put("eglx.gae",GAEActionStatementGenerator.class);

6. 代码生成器扩展

6.1 扩展代码生成器

    在完成EGL Model的定义和相应的Compiler注册以后,我们需要为这些新定义的EGL Model来定制和扩展相应的EGL Generator,用来产生和Google App Engine集成的Java代码。

    新建一个GAE模板项目org.eclipse.edt.gen.java.templates.eglx.gae(读者可以参考SQL相关的模板项目org.eclipse.edt.gen.java.templates.eglx.persistence),并创建相应的模板GAEAddStatementTemplate。源代码如下:

public class GAEAddStatementTemplate extends org.eclipse.edt.gen.java.templates.StatementTemplate {  
  
    public void genStatementBody(GAEAddStatement stmt, Context ctx, TabbedWriter out) {  
  
        Expression expression = stmt.getTarget();  
        Type type = expression.getType();  
  
        EGLClass targetType = (EGLClass) type.getClassifier();  
  
        String recordName = targetType.getName();  
  
        out.println("com.google.appengine.api.datastore.DatastoreService datastore = com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService();");  
        out.print("com.google.appengine.api.datastore.Entity ");  
        String googleEntity = "google_" + recordName;  
        out.print(googleEntity);  
        out.print(" = new com.google.appengine.api.datastore.Entity( " + "\"" + recordName + "\"" + " )");  
        out.print(";");  
        out.println();  
  
        for (Field f : targetType.getFields()) {  
  
            out.print(googleEntity + "." + "setProperty(\"");  
            ctx.invoke(genName, f, ctx, out);  
  
            TabbedWriter temp = ctx.getTabbedWriter();  
            ctx.invoke(genExpression, expression, ctx, temp);  
            String varName = temp.getCurrentLine();  
            out.print("\"," + varName + ".");  
            ctx.invoke(genName, f, ctx, out);  
            out.print(");");  
  
            out.println();  
        }  
  
        out.print("datastore.put(" + googleEntity + ");");  
  
    }  
}  
同时,需要创建一个模板文件用于把新定义的EGL Model和相应的Generator绑定在一起,源文件如下:

org.eclipse.edt.mof.eglx.gae.GAEAddStatement = org.eclipse.edt.gen.java.templates.eglx.gae.GAEAddStatementTemplate  
到此为止,和GoogleApp Engine数据存储集成相关的EGL扩展就完成了,接下来我们将给出一个样例来展示如何使用扩展后的EGL来实现和Google App Engine数据存储集成,并且部署到Google App Engine上。

7. 样例

7.1 开发样例程序

创建一个EGL RichUI项目“RuiTesting”,选择“Web2.0 client application withservices”作为模板。

在RuiTesting项目里,创建一个EGL Record,源代码如下:

record OrderItem  
    itemId int{@Id};//{@Id, @GeneratedValue };  
    //NAME string{@GeneratedValue};  
    name string{ @Column { insertable=true } };  
end  
创建一个EGL REST Service,源代码如下:
service HelloService  
    function sayHello(name string in) returns(string)  
        itemEntity OrderItem;  
        //ds SQLDataSource? = new SQLDataSource("jdbc:derby:C:/databases/EGLDerbyR7;create=true");    
        ds GAEDataSource? = new GAEDataSource();  
          
        add itemEntity to ds;  
        return("Hello World:" + name);  
    end  
end  
最后,创建一个RUI Handler来调用Service。在按钮的事件中来调用Service,源码如下。完整的程序,读者可以参考样例的下载。
function serviceButton_onClick(event Event in)  
        call helloService.sayHello(nameField.text) returning to handleReturn onException Exceptionhandler;  
    end  
      
    function handleReturn(results string in)  
        SysLib.writeStdout("Got service result:" + results);  
    end  
      
    private function Exceptionhandler( exception AnyException in)  
        handleException(exception, null);  
    end  
      
    private function handleException( exception AnyException in, srvc string? in)  
        SysLib.writeStdout(exception.message);  
    end  
EGL Service产生的Java代码如下,这里调用了Google AppEngine数据存储的API。
public String sayHello(String name) {  
        OrderItem itemEntity = new OrderItem();  
        GAEDataSource ds;  
        ds = new GAEDataSource();  
        com.google.appengine.api.datastore.DatastoreService datastore = com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService();  
        com.google.appengine.api.datastore.Entity google_OrderItem = new com.google.appengine.api.datastore.Entity( "OrderItem" );  
        google_OrderItem.setProperty("itemId",itemEntity.itemId);  
        google_OrderItem.setProperty("name",itemEntity.name);  
        datastore.put(google_OrderItem);;  
        return (("Hello World:") + name);  
    }  

7.2 部署并在本地运行

Google App Engine的Eclipse插件提供了本地的运行环境。因此,我们在这里介绍一下如何将7.1中开发的样例程序进行部署并在本地运行。

使用EGL Deployment Descriptor Editor来打开RuiTesting/EGLSource/RuiTesting.egldd文件,在Resource Binding标签中,设置URI为http://localhost:8888/restservices/HelloService

需要注意的是,由于GoogleApp Engine的Eclipse插件所提供的Web Application项目结构并非一个标准的Eclipse下的动态Web项目,为了EGL程序的部署需要,我们需要对GAE的项目结构做一些调整,使得它转换成一个标准的Eclipse动态Web项目。

首先创建一个Google App Engine的项目RuiTestingDeploy,在项目属性的Project Facet中设置DynamicWeb Module的版本为2.4。并设置WAR的目录为WebContent,如图所示。
设置WAR的目录

其次在原有的war目录下,将Google App Engine的部署描述符appengine-web.xml和Log4J的配置文件logging.properties拷贝到WebContent目录下。并删除原有的war目录。

    开始部署样例程序到RuiTestingDeploy中。部署完毕以后,修改下列文件:

  • src/RuiTestingDeploy-uri.xml。将contextroot元素的值设置为/restservices(如果开发的是Dedicated Service,则忽略这一步)。
  • WebContent/RuiTesting.html。将egl.initParams()函数的第一个参数设置为”.”。

   在GAE环境中,运行RuiTesting.html,关于怎么在本地运行GAE程序,读者可以参考GAE的官方文档。

8. 下一步

本篇博客只是对EGL中的add语句在GAE平台上的扩展做了初步探讨,接下来需要读者实现对EGL里的其它抽象操作语言(replace, delete和get)的扩展实现,并使用扩展后的基于GAE的EGL实现一个针对数据库访问的应用(前台使用EGLRichUI,后台使用基于GAE的EGL服务),并且需要部署在Google App Engine上。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值