转载

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

概述

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

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

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

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

点击查看大图

关闭 [x]

使用 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...