Functionsディレクトリの設定
次に、Functionsを設定してMuseum Finderアプリケーションのコーディングを開始します。
4つのJava Functionsはすべて、それぞれのFunctionディレクトリに以下のファイルを含みます:
- メインJava Functionファイル
- catalyst-config.json設定ファイル
- JARライブラリファイル
- .classpathおよび.project依存関係ファイル
Node.js Functionは、そのディレクトリに以下のファイルを含みます:
- index.jsメインFunctionファイル
- catalyst-config.json設定ファイル
- Nodeモジュール
- package.jsonおよびpackage-lock.json依存関係ファイル
各Java FunctionのメインJavaファイルと、Node.js Functionのindex.jsファイルにコードを追加します。
Functionの設定には任意のIDEを使用できます。
以下のコードをコピーして、functions/RatingProcessorディレクトリにあるRatingProcessor.javaに貼り付けて、ファイルを保存します。
import com.catalyst.Context;
import com.catalyst.basic.BasicIO;
import com.catalyst.basic.ZCFunction;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.logging.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.File;
import java.io.FileReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import com.zc.common.ZCProject;
import com.zc.component.cache.ZCCache;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class RatingProcessor implements ZCFunction {
private static final Logger LOGGER = Logger.getLogger(RatingProcessor.class.getName());
private static Map<String, Integer> map = new HashMap() {
{
put("Excellent",0);
put("Very good",1);
put("Average",2);
put("Poor",3);
put("Terrible",4);
}
};
@Override
@SuppressWarnings("unchecked")
public void runner(Context context, BasicIO basicIO) throws Exception {
try {
Integer topCount = 10;
if(basicIO.getParameter("count") != null) {
topCount = Integer.parseInt(basicIO.getParameter("count").toString());
}
String travellerRating = (String) basicIO.getParameter("type");
Integer type = 0;
if(travellerRating != null) {
if(map.containsKey(travellerRating)) {
type = map.get(travellerRating);
}
}
String url = "https://www.zoho.com/catalyst/downloads/static/tutorial/dataset/traveller-rating.json";
ZCProject.initProject();
HttpUrl.Builder httpBuilder = HttpUrl.parse(url).newBuilder();
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request.Builder requestsBuilder = new Request.Builder();
requestsBuilder.url(httpBuilder.build());
requestsBuilder.get();
Response responses = client.newCall(requestsBuilder.build()).execute();
String responsebody = responses.body().string();
JSONParser parser = new JSONParser();
JSONObject dataJSON = (JSONObject) parser.parse(responsebody);
HashMap<String, Long> execellentRating = new HashMap<>();
Iterator<String> itrJson = dataJSON.keySet().iterator();
while(itrJson.hasNext()) {
String museumName = itrJson.next();
List<String> ratingList = new ObjectMapper().convertValue(dataJSON.get(museumName), List.class);
Long exellentRating = Long.parseLong(ratingList.get(type));
execellentRating.put(museumName, exellentRating);
}
execellentRating = RatingProcessor.sortByValue(execellentRating);
List<String> execellentMuseum = new ArrayList<>();
itrJson = execellentRating.keySet().iterator();
Integer i= 0;
while(i++ < topCount && itrJson.hasNext()) {
execellentMuseum.add(itrJson.next());
}
basicIO.write(new ObjectMapper().writeValueAsString(execellentMuseum));
}
catch(Exception e) {
LOGGER.log(Level.SEVERE,"Exception in RatingProcessor",e);
basicIO.setStatus(500);
}
}
public static HashMap<String, Long> sortByValue(HashMap<String, Long> hm)
{
// HashMapの要素からリストを作成
List<Map.Entry<String, Long> > list =
new LinkedList<Map.Entry<String, Long> >(hm.entrySet());
// リストをソート
Collections.sort(list, new Comparator<Map.Entry<String, Long> >() {
public int compare(Map.Entry<String, Long> o1,
Map.Entry<String, Long> o2)
{
return (o2.getValue()).compareTo(o1.getValue());
}
});
// ソートされたリストのデータをHashMapに格納
HashMap<String, Long> temp = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> aa : list) {
temp.put(aa.getKey(), aa.getValue());
}
return temp;
}
}
以下のコードをコピーして、functions/TravellerTypeRatingProcessorディレクトリにあるTravellerTypeRatingProcessor.javaに貼り付けて、ファイルを保存します。
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.catalyst.Context;
import com.catalyst.basic.BasicIO;
import com.catalyst.basic.ZCFunction;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zc.common.ZCProject;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class TravellerTypeRatingProcessor implements ZCFunction {
private static final Logger LOGGER = Logger.getLogger(TravellerTypeRatingProcessor.class.getName());
private static Map<String, Integer> map = new HashMap() {
{
put("Families",0);
put("Couples",1);
put("Solo",2);
put("Business",3);
put("Friends",4);
}
};
@Override
public void runner(Context context, BasicIO basicIO) throws Exception {
try {
Integer topCount = 10;
String travellerType = (String) basicIO.getParameter("type");
Integer type = 0;
if(travellerType != null) {
if(map.containsKey(travellerType)) {
type = map.get(travellerType);
}
}
if(basicIO.getParameter("count") != null) {
topCount = Integer.parseInt(basicIO.getParameter("count").toString());
}
String url = "https://www.zoho.com/catalyst/downloads/static/tutorial/dataset/traveller-type-rating.json";
ZCProject.initProject();
HttpUrl.Builder httpBuilder = HttpUrl.parse(url).newBuilder();
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request.Builder requestsBuilder = new Request.Builder();
requestsBuilder.url(httpBuilder.build());
requestsBuilder.get();
Response responses = client.newCall(requestsBuilder.build()).execute();
String responsebody = responses.body().string();
JSONParser parser = new JSONParser();
JSONObject dataJSON = (JSONObject) parser.parse(responsebody);
HashMap<String, Long> execellentRating = new HashMap<>();
Iterator<String> itrJson = dataJSON.keySet().iterator();
while(itrJson.hasNext()) {
String museumName = itrJson.next();
List<String> ratingList = new ObjectMapper().convertValue(dataJSON.get(museumName), List.class);
Long rating = Long.parseLong(ratingList.get(type));
execellentRating.put(museumName, rating);
}
execellentRating = TravellerTypeRatingProcessor.sortByValue(execellentRating);
List<String> execellentMuseum = new ArrayList<>();
itrJson = execellentRating.keySet().iterator();
Integer i= 0;
while(i++ < topCount && itrJson.hasNext()) {
execellentMuseum.add(itrJson.next());
}
basicIO.write(new ObjectMapper().writeValueAsString(execellentMuseum));
}
catch(Exception e) {
LOGGER.log(Level.SEVERE,"Exception in TravellerTypeRatingProcessor",e); // このログはCatalystコンソールのLogsから確認できます
basicIO.setStatus(500);
}
}
public static HashMap<String, Long> sortByValue(HashMap<String, Long> hm)
{
// HashMapの要素からリストを作成
List<Map.Entry<String, Long> > list =
new LinkedList<Map.Entry<String, Long> >(hm.entrySet());
// リストをソート
Collections.sort(list, new Comparator<Map.Entry<String, Long> >() {
public int compare(Map.Entry<String, Long> o1,
Map.Entry<String, Long> o2)
{
return (o2.getValue()).compareTo(o1.getValue());
}
});
// ソートされたリストのデータをHashMapに格納
HashMap<String, Long> temp = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> aa : list) {
temp.put(aa.getKey(), aa.getValue());
}
return temp;
}
}
以下のコードをコピーして、functions/MergeDataSetディレクトリにあるMergeDataSet.javaに貼り付けて、ファイルを保存します。
import com.catalyst.Context;
import com.catalyst.basic.BasicIO;
import com.catalyst.basic.ZCFunction;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.logging.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import com.zc.common.ZCProject;
import com.zc.component.cache.ZCCache;
import com.zc.component.object.ZCTable;
public class MergeDataSet implements ZCFunction {
private static final Logger LOGGER = Logger.getLogger(MergeDataSet.class.getName());
@Override
public void runner(Context context, BasicIO basicIO) throws Exception {
try {
Object ratingList = basicIO.getArgument("rating_list");
Object typeRatingList = basicIO.getArgument("traveller_type_rating_list");
ObjectMapper mapper = new ObjectMapper();
List<String> travellerRatingList = mapper.readValue(ratingList.toString(), mapper.getTypeFactory().constructCollectionType(List.class, String.class));;
List<String> travellerTypeRatingList = mapper.readValue(typeRatingList.toString(), mapper.getTypeFactory().constructCollectionType(List.class, String.class));;
List<String> finalList = new ArrayList<>();
for(int i=0 ; i< travellerTypeRatingList.size() ; i++) {
if(travellerRatingList.contains(travellerTypeRatingList.get(i))) {
finalList.add(travellerTypeRatingList.get(i).toString());
}
}
JSONObject respJson = new JSONObject();
respJson.put("museum_list", finalList);
LOGGER.log(Level.INFO, "Museum Count"+finalList.size()); // このログはCatalystコンソールのLogsから確認できます
basicIO.write(new ObjectMapper().writeValueAsString(respJson));
}
catch(Exception e) {
e.printStackTrace();
LOGGER.log(Level.SEVERE,"Exception in MergeDataSet",e); // このログはCatalystコンソールのLogsから確認できます
basicIO.setStatus(500);
}
}
}
以下のコードをコピーして、functions/MailerディレクトリにあるMailer.javaに貼り付けて、ファイルを保存します。
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.simple.JSONObject;
import com.catalyst.Context;
import com.catalyst.basic.BasicIO;
import com.catalyst.basic.ZCFunction;
import com.zc.common.ZCProject;
import com.zc.component.mail.ZCMail;
import com.zc.component.mail.ZCMailContent;
public class Mailer implements ZCFunction {
private static final Logger LOGGER = Logger.getLogger(Mailer.class.getName());
private static final String SUBJECT = "Museum Search Results";
private static final String FROM_MAIL = "emma@zylker.com"; // 先ほど設定した送信者のメールアドレスを入力してください
@Override
public void runner(Context context, BasicIO basicIO) throws Exception {
try {
ZCProject.initProject();
Object content = basicIO.getArgument("content"); // MergeDataSet Functionから最終リストを取得
Object mailId = basicIO.getArgument("mail_id"); // 提供された入力からユーザーのメールアドレスを取得
if(content != null) {
String mailContent = content.toString();
ZCMailContent mail = ZCMailContent.getInstance();
mail.setSubject(SUBJECT);
mail.setFromEmail(FROM_MAIL);
if(mailId != null) {
mail.setToEmail(mailId.toString());
}
else {
basicIO.write(constructErrorMessage("mail_id not found"));
basicIO.setStatus(400);
return;
}
mail.setContent(mailContent);
mail.setHtmlMode(false);
ZCMail.getInstance().sendMail(mail);
basicIO.setStatus(200);
basicIO.write(constructSuccessMessage("Mail has been sent to "+mailId+" successfully"));
}
}
catch(Exception e) {
LOGGER.log(Level.SEVERE,"Exception in Mailer",e); // このログはCatalystコンソールのLogsから確認できます
basicIO.setStatus(500);
basicIO.write(constructErrorMessage(e.getMessage()));
}
}
private JSONObject constructErrorMessage(String message) {
JSONObject errorJSON = new JSONObject();
errorJSON.put("status", "failure");
errorJSON.put("message", message);
return errorJSON;
}
private JSONObject constructSuccessMessage(String message) {
JSONObject errorJSON = new JSONObject();
errorJSON.put("status", "success");
errorJSON.put("message", message);
return errorJSON;
}
}
Expressのインストール
Node.js Functionのコーディングを行う前に、ディレクトリにExpress Node.jsの依存関係をインストールする必要があります。
ローカルマシンにExpress.jsをインストールするには、ターミナルでFunctionのディレクトリ(functions/circuit)に移動し、以下のコマンドを実行します:
これにより、Expressモジュールがインストールされ、依存関係が保存されます。
この情報はpackage.jsonファイルにも更新されます。
次に、index.jsファイルをコーディングしましょう。
以下のコードをコピーして、functions/circuitディレクトリにあるindex.jsに貼り付けて、ファイルを保存します。
'use strict';
var express = require('express');
var app = express();
var catalyst = require('zcatalyst-sdk-node');
app.use(express.json());
app.post('/triggerCircuit', (req, res) => {
var CatalystApp = catalyst.initialize(req);
var body = req.body;
console.log(body);
let execName = new Date().getTime().toString();
console.log(execName);
let promiseResult = CatalystApp.circuit().execute("1028000000084051",execName, body); // コンソールで作成したCircuitのCircuit IDを入力してください
promiseResult.then((functionResponse) => {
console.log(functionResponse);
res.status(200).send({ message: "Please check your email for the list of museums." });
}).catch(err => {
console.log(err); // このログはCatalystコンソールのLogsから確認できます
res.status(500).send({ message: "Please try again after sometime!" });
})
});
module.exports = app;
設定したFunctionsについて簡単に確認しましょう。
Circuit:
-
Advanced I/O circuit Functionには、CatalystコンソールでConfigure済みのCircuitの実行をトリガーするAPI /triggerCircuitが含まれています。
Note: Circuitは、プロジェクトリソースをリモートコンソールにデプロイした後に設定します。 -
circuit Functionは、クライアントアプリケーションでエンドユーザーから取得した入力データを、実行のトリガー時にCircuitに渡します。このデータは、クライアントディレクトリのmain.jsによってCircuit Functionに渡されます。
-
Circuitの実行が完了すると、ユーザーの条件を満たす博物館のリストをメールで確認するよう促すメッセージがクライアントアプリケーションに表示されます。このメッセージはこのFunctionで設定されています。
RatingProcessorとTravellerTypeRatingProcessor:
- RatingProcessor Functionは、博物館の以下の評価をJava HashMapに格納します:Excellent、Very Good、Average、Poor、Terrible。
- TravellerTypeRatingProcessor Functionは、博物館の以下の旅行者タイプ適合性をJava HashMapに格納します:Families、Couples、Solo、Business、Friends。
- 評価と旅行者タイプに加えて、ユーザーは結果に表示したい博物館の数を入力します。この値はcount変数に格納され、両方のFunctionsで処理されます。
- Functionsは、Catalystがホストするtraveller-rating.jsonまたはtraveller-type-rating.jsonデータセットをそれぞれ呼び出します。これらのデータセットには、さまざまなウェブサイトでユーザーが提供した評価や旅行者タイプの適合性のレコードが含まれています。
- ユーザーが提供した入力に基づいて、両方のFunctionsがこれらのデータセットからレコードを取得します。例えば、ユーザーが評価タイプとしてExcellentを選択した場合、traveller-rating.jsonデータセットでその評価を持つ博物館が特定されます。ユーザーが提供したcount値を超えない範囲で、Excellent評価が最も多い博物館が降順にソートされて取得されます。ユーザーが提供した旅行者タイプの入力に一致するレコードも、同様にtraveller-type-rating.json dataset.から取得されます。
- 両方のFunctionsが取得したレコードはJSONオブジェクトとしてパースされ、ObjectMapperクラスに書き込まれます。その後、リストでソートされ、両方のFunctionsで新しいHashMapに追加されます。
MergeDataSet:
- MergeDataSet Functionは、RatingProcessorとTravellerTypeRatingProcessor Functionsが取得したレコードを引数として受け取ります。
- このFunctionは両方のリストの共通部分を求め、両方のリストに存在する博物館の結果を確認します。
- 両方のリストに存在する博物館を最終リストに追加し、そのリストをJSONレスポンスとして返します。
Mailer:
- Mailer Functionは、設定するCircuit内のMergeDataSet Functionから最終リストを取得します。これがメールの本文として設定されます。また、ユーザーが入力したメールアドレスも取得します。
- このFunctionでメールの件名と送信者アドレスを設定できます。Mailer Functionは、取得したコンテンツを含むメールをユーザーのメールアドレスに送信します。
Functionsディレクトリの設定が完了しました。
最終更新日 2026-03-05 11:43:24 +0530 IST