内容


使用 Bluemix 中的 Rules 服务构建一个酒店预订应用程序

Comments

Rules 服务托管在 Bluemix 中,由 Operational Decision Manager 提供支持,它允许您在独立于应用程序代码的情况下在 RuleApp 中定义、部署和维护业务规则与策略,提供更好的应用灵活性。您可以在 RuleApp 中更新业务逻辑并重新部署它,同时不对预订应用程序进行任何修改,从而减少花费在记录与测试业务策略变更上的时间,比如定价计算、合格鉴定或信用授权。

为了演示将业务逻辑与云中运行的调用应用程序分离的好处,我们将引领您逐步构建一个利用 Rules 服务的示例应用程序。然后您就能够非常轻松地使用更加复杂的规则扩展此应用程序或者构建您自己的应用程序。

此预订应用程序示例显示了将 Rules 服务与云中 Node.js 应用程序相集成的可能性,同时还利用了 Bluemix 平台的部署简便性与可扩展性。

我们的示例应用程序针对的是一家正构建其预订系统并希望为其客户提供应用程序来搜索和预订房间的连锁酒店。酒店所有者需要定义各种业务策略来计算预订率,比如提前订房的折扣或最后一分钟订房的订单。他们可能需要修改这些策略,以适应各种旅游季节和特殊情况。他们还希望在未来添加更多关于特价房或忠诚度计划的策略。

为了实现这一切,我们将使用 Node.js 构建一个应用程序,并使用 Rules 服务轻松管理和执行定义这些策略的业务规则。与此同时,我们还将利用 Bluemix 平台的部署方便性与可扩展性。

运行应用程序Get the code

构建应用程序的前提条件

  1. 熟悉 Node.js
  2. 一些 Node.js 模块: Express 框架EJSasync
  3. 对 HTML 和 Bootstrap 3 CSS 有基本的了解。
  4. IBM Operational Decision Manager (ODM) 有基本的了解(推荐)。
  5. Eclipse IDE for Java EE Developers。安装 Rule Designer 插件
  6. Cloud Foundry cf Command-Line Interface V6。从 GitHub 下载并运行安装程序。

构建酒店预订应用程序

步骤 1. 在 Bluemix 中创建一个 Rules 服务实例

  1. 在 Bluemix 目录中选择 Rules 服务,然后单击 CREATE AND ADD TO APP。给服务命名,然后选择 [Do not associate]。(在下一步骤中,要将服务绑定到应用程序。)单击 CREATE该图显示正在创建 Rules 服务
    该图显示正在创建 Rules 服务
  2. 单击您创建的 Rules 服务实例,然后注意 BlueBooking-Rules 面板上的以下信息:
    • Administration Console URL and credentials(用于规则集部署)
    • Execution Endpoint URL(用于规则集执行)
    该图显示了 BlueBooking-Rules 屏幕
    该图显示了 BlueBooking-Rules 屏幕

步骤 2. 使用 Rule Designer 定义应用程序业务逻辑

在这个步骤中,您将了解在 Rule Designer 中编写业务规则所需的核心概念与行为。不过,本文的重点并不是提供关于这一点的详细说明,有关的更多信息,可以参见下面的文章。

在继续这个步骤之前:

  • 确保已经在 Eclipse IDE 中安装了 Rule Designer 插件
  • 查看来自 Git 库的 BlueBookingXomBlueBookingRules 项目:
    git 克隆 https://hub.jazz.net/git/rulesservicesample/BlueBookingV1
  • 将它们导入到 Eclipse 工作区中,然后切换至 Rule 视图,以便打开 Rule Explorer该图显示了 Rule Designer 中的示例应用程序项目的工作区结构
    该图显示了 Rule Designer 中的示例应用程序项目的工作区结构

1. 定义执行对象模型 (XOM)

执行对象模型 (XOM) 是执行规则的运行时模型。IBM Operational Decision Manager (ODM) 支持根据 Java™ 或 XML 源代码构建的执行对象模型。为了达到本文的目的,我们将使用一个基于 Java 的简单 XOM,这个 XOM 是在 BlueBookingXom Java 项目中定义的,它包含两个类:

  1. Hotel 类代表一家酒店,具有以下属性:
    • 酒店名称
    • 酒店位置(城市)
    • 一个房间的基本费率
  2. Result 类定义了客户请求的结果,具有以下信息:
    • 酒店
    • 入住日期
    • 结账离开日期
    • 根据业务规则执行计算出的预订率

2. 指定业务对象模型

业务对象模型 (BOM) 是编辑规则的模型。通常会根据现有的 XOM 源代码创建 BOM 条目。在我们的例子中,BlueBookingRules Rule 项目已经包含一个根据 BlueBookingXom Java XOM 创建的 BOM 条目。

3. 编写业务逻辑

现在可以编写应用程序业务逻辑了。示例的 BlueBookingRules Rule 项目包含 advanceReduction 决策表与 bluebooking 规则流。

advanceReduction 决策表根据预定时间的早晚程度来计算折扣金额。

该图显示了决策表是如何计算折扣的
该图显示了决策表是如何计算折扣的

bluebooking 规则流将执行定义为两个连续的任务:initReservationpricing

  • initReservation 用于初始化执行规则后返回的 Result 实例。
  • pricing 用于触发将要应用的折扣计算。
该图显示了 BlueBookingRules 流
该图显示了 BlueBookingRules 流

4. 定义业务逻辑与客户端应用程序之间的契约

规则集参数指定了业务逻辑与客户端应用程序之间的契约。在这个例子中,存在:

  • 三个输入参数:酒店、入住日期和结账离开日期
  • 一个在业务逻辑执行后传递给客户端应用程序的输出参数:一个 Result 类的实例
该图显示了规则集参数
该图显示了规则集参数

步骤 3. 在 Bluemix 中将业务逻辑部署到 Rules 服务

在继续这个步骤之前,您可能希望让自己熟悉业务规则应用程序的架构:

在 Rule Designer 中创建 RuleApp 项目

您将通过一个 RuleApp 项目来部署业务规则:

  1. Rule Explorer 视图中,选择 BlueBookingRules Rule 项目。
  2. Rule Project Map 视图的 Deploy and Integrate 部分单击 Create RuleApp project 链接。
  3. New RuleApp Project 向导中,将项目名称设置为 BlueBookingRuleApp,然后单击 Finish。您的工作区中将会创建一个包含 BlueBookingRules Rule 项目的 RuleApp 新项目(作为规则集)。

在 Bluemix 中将 RuleApp 部署到 Rules 服务

现在,您就可以将您的 RuleApp 部署到 Rules service:

  1. Rule Explorer 视图中,选择 BlueBookingRuleApp 项目。
  2. 右键单击 RuleApp 项目,然后选择 RuleApp > Deploy
  3. Deploy RuleApp Archive 向导中单击 Next,以便保持针对 RuleApp 与规则集部署的默认版本控制策略。如果使用了 JDK 7,则会打开一个警告对话框。单击 OK 关闭它。
  4. 在下一个向导页面上,选择 Create a temporary Rule Execution Server configuration。填入 Administration Console 的 URL、登录名称和密码,以及 Rules 服务实例的相应信息。单击 Finish该图显示了如何将 RuleApp 部署到 Rules 服务
    该图显示了如何将 RuleApp 部署到 Rules 服务

    如果一切正常,那么 Console 将会显示一条成功消息: 该图显示了成功消息
    该图显示了成功消息

步骤 4. 在 Bluemix 中构建一个 Node.js Express 应用程序

1. 创建一个 Node.js 启动器应用程序并将它绑定到 Rules 服务

  1. 在 Bluemix 目录中,选择 Node.js 运行时,然后单击 CREATE APP。为应用程序命名并提供一个主机 URL,后者将作为应用程序在 Internet 上的访问点,例如 mybookingapp.mybluemix.net。然后单击 CREATE该图显示正在创建应用程序
    该图显示正在创建应用程序
  2. 选择应用程序,然后单击 Bind a service。选择在前一步骤中创建的 Rules 服务实例,然后单击 OK。Rules 服务现在已被绑定到您的应用程序。 图像显示了现在已被绑定到您的应用程序的 Rules 服务
    图像显示了现在已被绑定到您的应用程序的 Rules 服务
  3. 现在您可以下载由 Bluemix 生成的示例启动器,并进行一些修改。单击 VIEW > GUIDE,然后单击 Download the starter application package 来下载 ZIP 文件,并将它解压缩到您的文件系统中。

2. 添加和下载依赖项

让我们从向依赖项添加必要的 Node.js 模块开始。在 package.json 文件中修改应用程序名称、描述与依赖项。

{
	"name": "mybookingapp",
	"version": "0.0.1",
	"description": "A simple hotel booking app using Rules Service in BlueMix",
	"dependencies": {
		"express": "3.4.7",
		"ejs": "0.8.5",
		"async": "0.7.0"
	},
	"engines": {
		"node": "0.10.0"
	},
	"repository": {}
}

在应用程序的根目录中运行 npm install 命令,将依赖项下载到 node_modules 目录中。

3. 绘制一个页面来搜索酒店

在示例中,我们选择使用 EJS 作为模板引擎,因为它使用的是标准的 HTML 语法。但您也可以使用其他任意模板引擎,比如 Jade、Hogan 或 Underscore。

  1. 修改 'view engine' 配置参数,将它变为应用程序的默认值:
    	app.set('view engine', 'ejs');
  2. 在项目的 views 文件夹中创建一个 index.ejs 文件,同时创建一个包含三个输入内容的 HTML 表单:城市、入住日期和结账离开日期,以便利用它们来来搜索酒店。您可能希望让页面变得更加美观,并在 Bootstrap 的帮助下能够适应各种屏幕大小,但我们在本文中不会详细讨论 HTML 标记和 CSS 样式的内容。另外,您可以从 Git 库中的 BlueBookingServer 项目复制和粘贴代码。
  3. index.ejs 完成时,只需将默认请求路由到这个主页面即可。
    // Main app page
    app.get('/', function(req, res){
      res.render('index');
    });

4. 在一个城市中搜索酒店

提交搜索表单时,GET 请求被路由到 /hotels。我们想从请求中提取参数,从而在被请求的城市中找到可用酒店的列表。请注意,日期是使用协调世界时间 (UTC, Coordinated Universal Time) 时区进行解析的。

// Hotel search results
app.get('/hotels', function(req, res){
  // get the request parameters
  var city = req.query.city;
  // the date string is in mm/dd/yyyy format
  var fromDateStr = req.query.from;
  var toDateStr = req.query.to;
  // parse the date string in UTC timezone
  var fromDate = Date.UTC(fromDateStr.split('/')[2], fromDateStr.split('/')[0]-1, fromDateStr.split('/')[1]);
  var toDate = Date.UTC(toDateStr.split('/')[2], toDateStr.split('/')[0]-1, toDateStr.split('/')[1]);
  … //render the page
});

为了简便起见,我们不会在这个示例应用程序中通过数据库查询酒店。相反,我们加载了一个数据文件 (data/hotels.json),然后为所请求城市返回一个酒店数组。

function findHotels(city) {
  var hotels = require(__dirname + '/data/hotels.json');
  return hotels[city];
}

5. 调用 Rules 服务获取结果

当我们将 Rules 服务绑定到应用程序时,会将服务配置添加到 VCAP_SERVICES,这是应用程序的一个只读环境变量。您可以在显示面板中看到它。

{
{
  "Rules-8.5.1": [
    {
       "name": "BlueBooking-Rules",
       "label": "Rules-8.5.1",
       "plan": "free",
       "credentials": {
          "executionRestUrl": "http://ds-XXXXX.ng.bluemix.net/DecisionService/rest",
          "executionSoapUrl": "http://ds-XXXXX.ng.bluemix.net/DecisionService/ws",
          "executionAdminUrl": "https://ds-XXXXX.ng.bluemix.net/res",
          "executionAdminRestUrl": "https://ds-XXXXX.ng.bluemix.net/res/api",
          "user": "username",
          "password": "password"
       }
    }
  ]
}
  1. 通过调用执行 REST API 可以执行在 Rules 服务中部署的规则集。您需要解析 VCAP_SERVICES 变量,并在应用程序中使用它来获取 REST 执行端点。
    // Retrieve the Rules Service parameters
    if (process.env.VCAP_SERVICES) {
      var env = JSON.parse(process.env.VCAP_SERVICES);
      var rules = env['Rules-8.5.1'][0].credentials;
    } else {
      // for local testing, set the execution endpoint manually
      var rules = {
    	"executionRestUrl": "http://ds-XXXXX.ng.bluemix.net/DecisionService/rest",
      };
    }
  2. 然后,在 Node.js 应用程序中,您可以加载 httpsurl 模块,然后使用它们对 REST 客户端进行编码。
    var https = require('https')
      , url = require('url');
  3. 创建一个采用以下参数的实用工具函数(invokeRulesService):
    • rulesetPath:一个 /{ruleappName}/{ruleappVersion}/{rulesetName}/{rulesetVersion} 格式的字符串。Rules 服务支持 RuleApps 和规则集的版本控制。如果不指定版本,则会自动使用最新版本。
    • inputParam:一个包含规则集输入参数容量的 JSON 对象。
    • callback:一个用于响应的回调函数,因为 HTTP 请求是异步的。
  4. 该函数将向 executionRestUrl+rulesetpath 发起一个 POST 请求,同时将 Content-Type 设置为 application/json 和请求主体中的规则集输入参数。Rules 服务将执行规则集,并在 JSON 格式的响应体中返回输出值。
    function invokeRulesService(rulesetPath, inputParams, callback) {
      var restUrl = url.parse(rules.executionRestUrl);
      var dataString = JSON.stringify(inputParams);
      headers = {
        'Content-Type': 'application/json',
        'Content-Length': dataString.length
      };
      var options = {
        host: restUrl.host,
    	path: restUrl.path + rulesetPath,
        method: 'POST',
        headers: headers
      };
    
      var req = https.request(options, function(resp) {
        resp.setEncoding('utf-8');
        var responseString = '';
    
        resp.on('data', function(data) {
          responseString += data;
        });
    
        resp.on('end', function() {
          console.log(responseString);
          var responseObject = JSON.parse(responseString);
          callback(responseObject);
        });
      });
      
      req.write(dataString);
      req.end();
    }
  5. 最后,您可以使用实用工具函数对每家酒店调用 Rules 服务,以便获得带入住率的结果。确保规则集路径的正确性,而且输入参数名称就是规则集中定义的那些名称。因为对 Rules 服务的调用是异步的,所以您可以使用 async 模块对酒店数组进行迭代,并在所有调用完成时返回一个结果数组。不要忘记导出此函数,以便从 app.js 调用它。
    /*
     * Invoke the Rules Service to calculate the rate for each of the hotels
     */
    function getResults(city, fromDate, toDate, callback) {
        var results = new Array();
        var rulesetPath = '/BlueBookingRuleApp/BlueBookingRules/';
        var hotels = findHotels(city);
        async.each(hotels, function(hotel, callback) {
    	  var inputParams = {"hotel": hotel, "checkin": fromDate, "checkout": toDate};
    	  invokeRulesService(rulesetPath, inputParams, function(responseObj) {	  
    		results.push(responseObj['result']);
    		callback();
    	  });	  
        }, function(err) {
          if (err) {
            console.log(err);
          } else {
            callback(results);
          }
        });
    }
    // export public functions
    exports.getResults = getResults;

6. 显示结果

回到 app.js;现在可以使用 Rules 服务返回的结果来呈现 hotel.ejs 页面。

service.getResults(city, fromDate, toDate, function(results){
    // render the page with data
    res.render('hotels', {"city": city, "from": req.query.from, "to": req.query.to, "results": results});
  });

步骤 5. 在 Bluemix 中推送和运行应用程序

现在,我们可以将 Node.js 应用程序推送给 Bluemix。在项目文件夹中可以找到一个 manifest.yml 文件,该文件用于描述 Bluemix 中应用程序的名称和域、创建实例的数量、分配的内存,等等。

  1. 使用命令行 cf login -a api.ng.bluemix.net 登录 Bluemix。根据提示输入您的用户名、密码、组织和空间。
  2. 通过运行 cf push 将应用程序部署到 Bluemix。
  3. 在运行应用程序的时候访问 http://mybookingapp.mybluemix.net,以便测试应用程序。

结束语

Rules 服务允许您将业务逻辑与应用程序逻辑分离,从而获得更大的应用灵活性。您可以更新业务逻辑,然后重新部署 RuleApp,同时不对预订应用程序进行任何修改,减少花费在记录与测试业务策略变更上的时间,比如定价计算、合格鉴定或信用授权。此预订应用程序示例显示了将 Rules 服务与云中 Node.js 应用程序相集成的可能性,同时还利用了 Bluemix 平台的部署简便性与可扩展性。

致谢

非常感谢 Frederic Lavigne 和 Laurent Grateau 的鼓励与帮助,并感谢 Christiane Mosbach 对本文档的审阅。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Cloud computing
ArticleID=980495
ArticleTitle=使用 Bluemix 中的 Rules 服务构建一个酒店预订应用程序
publish-date=08142014