转载

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

概述

一个电子商务 Web 应用程序每天晚上都要处理当天收到的所有订单,并通过电子邮件向客户告知订单状态的变化。

自动执行此流程会为此 Web 应用程序的开发人员和管理员节省大量的时间,这时 IBM Workload Scheduler 就变得非常有用。

事实上,它允许您自动调度各种操作,这大大缩短了应用程序的开发时间并简化了它的管理工作。

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

点击查看大图

要在 Bluemix 上实现此场景,我们可充分利用该平台提供的各种服务,并且您可轻松地将这些服务集成到应用程序中。

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

为了在每晚调度订单流程,我们当然能使用 Workload Scheduler 服务,我们将使用此服务在应用程序中定期调用 REST API,该 API 实现的业务逻辑可处理各种订单。

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

此外,我们需要一个数据库来存储订单、电子邮件地址和其他客户信息,为此,我们决定使用一个 no-SQL 数据库,然后使用 Cloudant 服务。

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

我们还需要一个服务来发送电子邮件,我们决定使用 SendGrid 服务。

在另一篇文章中,我介绍了一个使用 IWS Node.js 库来实现此用例的解决方案。

所以,如果您对此应用程序的 Node.js 版本感兴趣,或者希望了解完整的场景,可通过此链接找到该文章:

使用 Bluemix 上的 IBM Workload Scheduler Node.js 客户端库处理客户订单

在本文中,您刚才已看到我将使用 Liberty 运行时实现相同的用例,而且将使用 IWS Java 客户端库。

下面简要介绍一下完整的代码。


在 Java 中编写应用程序

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

单击此处将此应用程序的 Java 版本部署到您的 Bluemix 帐户:

使用 Workload Scheduler 服务实现每晚运行一个流程的示例 Java 应用程序

在本例中,WebUI 是位于 WebContent 文件夹中的 index.jsp 文件,这与 Node.js 代码版本几乎相同,但此页面上的表单会自动将请求提交到同一个 index.jsp 文件。

首先,创建一个 com.ibm.twa.bluemix.samples.ProcessOrdersIWS 对象并将其添加到会话中,如果该对象已存在,则加载它:

 <%@page  import="com.ibm.twa.bluemix.samples.ProcessOrdersIWS"%>  <%!  //Session key to register in the session  private static final String WORKLOAD_APP_SESSION_KEY =  "WORKLOAD_APP";  %>  <%  ProcessOrdersIWS poApp;  if  (session.getAttribute(WORKLOAD_APP_SESSION_KEY)!=null){  poApp = (ProcessOrdersIWS)  session.getAttribute(WORKLOAD_APP_SESSION_KEY);  }else{  poApp = new ProcessOrdersIWS();    session.setAttribute(WORKLOAD_APP_SESSION_KEY,poApp);  }  %>

这个类是此应用程序的主要类,充当着控制器,所以它在各种管理器(我们将会介绍)之间分配职责……

private CloudantManager cManager = new CloudantManager();  private WorkloadSchedulerManager wsManager = new WorkloadSchedulerManager();

按以下顺序使用这些方法:

1.appConnect:初始化与 WorkloadScheduler 和 Cloudant 服务的连接;

public void appConnect() throws JSONException {  Manager.initConnection();  wsManager.initConnection();  }

2.isConnected:检查连接方法是否成功执行;

public boolean isConnected() {  return this.wsManager.isConnected() &&  this.cManager.isConnected();  }

3.appCheckOrCreateProcess:检查是否存在一个 WS 流程,如果不存在,则创建它;

public void appCheckOrCreateProcess() throws  InvalidRuleException, WorkloadServiceException, Exception  {  this.wsManager.appCheckOrCreateProcess();  }

4.existProcess:检查该流程是否存在;

public boolean existProcess() {   return this.wsManager.isProcessExist(); }

5.postSubmission:创建一个提交并将其保存到 Cloudant 数据库中;

public void postSubmission(String address, String subject, String body) throws Exception {  this.cManager.postSubmission(address, subject,body);  }

6.isSubmitted:检查提交是否已成功保存;

public boolean isSubmitted(){  return this.cManager.isSubmitted();  }

所有这些方法都被路由到一个或多个扩展 com.ibm.twa.bluemix.samples.managers.Manager 类的类。

所以 Manager 是一个抽象类,它包含:

initConnection():此方法向 VCAP_SERVICES 环境变量检索一个通用服务的凭据并使用它进行连接。要想正常运行,此方法需要一个能够从 VCAP_SERVICES 获取每个服务的正确凭据的 switch:

switch(this.serviceName){  case "cloudantNoSQLDB":  this.user = (String) credentials.get("username");  this.host = (String) credentials.get("host");  this.password = (String)  credentials.get("password");  this.url = (String) credentials.get("url");  this.port = (int) credentials.get("port");  break;  case "WorkloadScheduler":  this.user = (String) credentials.get("userId");  this.password = (String)  credentials.get("password");  this.url = (String) credentials.get("url");  break;  case "sendgrid":  this.user = (String) credentials.get("username");  this.password = (String)  credentials.get("password");  this.host = (String) credentials.get("hostname");  break;  }

它还需要通过构造函数方法获取具体的服务名称:

public Manager(String serviceName){  this.serviceName = serviceName;  }

connect():这是一个由特定服务所实现的抽象方法(所有类都扩展了 Manager.java),并通过以下方式创建与这些服务的连接:

WorkloadSchedulerManager:  public void connect() {  try {  this.ws = new WorkloadService(this.getUrl());  } catch (MalformedURLException e) {  e.printStackTrace();  } catch (WorkloadServiceException e) {  e.printStackTrace();  }  }  CloudantManager:  public void connect(){  this.cloudantClient = new CloudantClient(this.getUrl(),  this.getUser(), this.getPassword());  }  SendGridManager:  public void connect(){  this.sendgrid = new SendGrid(this.getUser(),  this.getPassword());  }

现在我们可将精力放在包 com.ibm.twa.bluemix.samples.managers 中已扩展的管理器的最重要具体方法上:

在 WorkloadSchedulerManager 中,我们可找到 appCheckOrCreateProcess() 方法,它负责:

1. 按名称获取一个流程库,或者如果该库不存在,则创建一个

TaskLibrary lib =  this.getProcessLibraryByName(WorkloadSchedulerManager.processLibraryName);  if(lib == null){  System.out.println("Library not found");  System.out.println("Creating library...");  lib = new TaskLibrary();  lib.setName(WorkloadSchedulerManager.processLibraryName);  lib.setParentId(-1);  lib = ws.createTaskLibrary(lib);  } else{  System.out.println(lib.getName() + " process library  found");  }

2. 按名称以及刚获取的流程库获取一个流程……

Task task = this.getProcessByName(lib, WorkloadSchedulerManager.processName);

3. 如果该流程不存在,则通过以下方式创建它:

// Create the Workload Automation Process   WAProcess process = new WAProcess("processOrdersIWS", "Process  orders using IWS");  // Retrieve the tenantId value (from the url  property)  int index = super.getUrl().indexOf("tenantId=") + 9;  String prefix = super.getUrl().substring(index, index +  2);  this.agentName = prefix + "_CLOUD";  // Set the Restful URL   String url =  "http://www.yourapp.mybluemix.net/api/sendemail/";  // Create the RestfulStep object and add it to the Workload  Automation Process  RestfulStep restStep = new RestfulStep(agentName, url,  "application/json",   "application/json", RestfulStep.GET_METHOD);  process.addStep(restStep);  process.setTaskLibraryId(lib.getId());  // Create a trigger that allows to the Workload Automation  process  // to run every night at the 23:00 (11PM)  Trigger trigger = TriggerFactory.everyDayAt(23, 00);  process.addTrigger(trigger);  // Create and Enable the Workload Automation Process  // After being instantiated, a process has to be created and  activated   // on the server before it can be triggered to run according    // to the specified schedule.  try {  System.out.println("Creating and enabling the  process");  Task createdTask = ws.createAndEnableTask(process);  this.myProcessId = createdTask.getId();  this.processExist = true;  } catch (Exception e) {  System.out.println(e.getClass().getName() + " " +  e.getMessage());  }

在 CloudantManager 中,我们可找到:

1.postSubmission(String address, String subject, String body),它创建一个提交并将其保存在数据库上

public Response postSubmission(String address, String subject,  String body) throws Exception {  if(this.cloudantClient == null){  this.connect();  }  this.subId = UUID.randomUUID().toString();  Submission submission = new Submission(this.subId, address,  subject, body);  Database db =  this.getDbByName(CloudantManager.cloudantDatabaseName);  Response response = db.post(submission);  this.submitted = true;  return response;  }

2.getAllSubmissions(),它检索并返回数据库上已保存的所有提交

public List getAllSubmissions() throws  JSONException{  this.db =  this.getDbByName(CloudantManager.cloudantDatabaseName);  if(db != null){  this.submissions =  db.view("_all_docs").includeDocs(true).query(Submission.class);  }  return this.submissions;  }

3. 在 SendGridManager 中,我们可找到 send() 方法

public String send() throws JSONException{  if(!this.isConnected()){ this.initConnection(); }  if(!this.cManager.isConnected()){ this.cManager.initConnection();  }  this.submissions =  this.cManager.getAllSubmissions();  String resp = "Email sent to:</br>";  SendGrid.Response response = null;  for(Submission sub : this.submissions){  if(!sub.getStatus().equalsIgnoreCase("completed")){  this.sgemail = new SendGrid.Email();  try {  System.out.println("Sending email to:" +  sub.getAddress());  this.sgemail.addTo(sub.getAddress());  this.sgemail.setFrom("gabdibonaventura@gmail.com");  this.sgemail.setSubject(sub.getSubject());  this.sgemail.setText(sub.getBody());  response = this.sendgrid.send(this.sgemail);  } catch (SendGridException e) {  e.printStackTrace();  sub.setStatus("failed");  this.cManager.getDb().update(sub);  }  if(response.getStatus()){  resp += sub.getAddress() + "</br>";  sub.setStatus("completed");  this.cManager.getDb().update(sub);  } else{  resp += sub.getAddress() + " not sent because:" +  response.getMessage();  sub.setStatus("failed");  this.cManager.getDb().update(sub);  }  }  this.sgemail = null;  }  return resp;  }

Submission 类帮助我们管理 Cloudant 文档,它包含电子邮件细节(地址、主题和正文),提交日期和提交状态(“submitted”、“completed”或“failed”)等信息。

package com.ibm.twa.bluemix.samples.helpers;  import java.util.Calendar;  public class Submission {  private String _id;  private String _rev;  private String address;  private String subject;  private String body;  private String status;  private Calendar startDate;  public Submission(String _id, String address, String subject,  String body){  this._id = _id;  this.address = address;  this.subject = subject;  this.body = body;  this.status = "submitted";  this.setStartDate(Calendar.getInstance());  }  //getters and setters  }

Workload Scheduler 步骤中 REST 风格的调用被提交到 com.ibm.twa.bluemix.samples.jaxrs.SendEmail 类,具体来讲提交到 sendEmail() 方法。

public Response sendEmail() throws SendGridException,  JSONException {  this.sgManager = new SendGridManager();  this.sgManager.initConnection();  String response = this.sgManager.send();  return Response.ok().entity(response).build();

现在您已准备好将此应用程序部署在 Bluemix 环境上,并轻松、快速地完成您的工作。一个在几年前需要经验丰富的程序员参与并且需要大量时间的工作,现在只需几次单击即可完成,然后您只需单击代码概述内容顶部的 Deploy 按钮。


正文到此结束
Loading...