Configurar el Directorio de Functions
A continuación, comenzaremos a codificar la aplicación Museum Finder configurando las funciones.
Las cuatro funciones Java contienen los siguientes archivos en sus directorios de función individuales:
- El archivo principal de la función Java
- El archivo de configuración catalyst-config.json
- Los archivos de biblioteca JAR
- Los archivos de dependencias .classpath y .project
La función Node.js contiene los siguientes archivos en su directorio:
- El archivo principal de la función index.js
- El archivo de configuración catalyst-config.json
- Los módulos de Node
- Los archivos de dependencias package.json y package-lock.json
Agregaremos código en los archivos principales de Java de cada función Java y en el archivo index.js de la función Node.js.
Puedes usar cualquier IDE de tu elección para configurar la función.
Copia el código a continuación y pégalo en RatingProcessor.java ubicado en el directorio functions/RatingProcessor y guarda el archivo.
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)
{
// Crear una lista a partir de elementos del HashMap
List<Map.Entry<String, Long> > list =
new LinkedList<Map.Entry<String, Long> >(hm.entrySet());
// Ordenar la lista
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());
}
});
// Colocar los datos de la lista ordenada en el HashMap
HashMap<String, Long> temp = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> aa : list) {
temp.put(aa.getKey(), aa.getValue());
}
return temp;
}
}
Copia el código a continuación y pégalo en TravellerTypeRatingProcessor.java ubicado en el directorio functions/TravellerTypeRatingProcessor y guarda el archivo.
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); //Puedes ver este log desde Logs en la consola de Catalyst
basicIO.setStatus(500);
}
}
public static HashMap<String, Long> sortByValue(HashMap<String, Long> hm)
{
//Crear una lista a partir de elementos del HashMap
List<Map.Entry<String, Long> > list =
new LinkedList<Map.Entry<String, Long> >(hm.entrySet());
//Ordenar la lista
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());
}
});
//Colocar los datos de la lista ordenada en el HashMap
HashMap<String, Long> temp = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> aa : list) {
temp.put(aa.getKey(), aa.getValue());
}
return temp;
}
}
Copia el código a continuación y pégalo en MergeDataSet.java ubicado en el directorio functions/MergeDataSet y guarda el archivo.
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()); //Puedes ver este log desde Logs en la consola de Catalyst
basicIO.write(new ObjectMapper().writeValueAsString(respJson));
}
catch(Exception e) {
e.printStackTrace();
LOGGER.log(Level.SEVERE,"Exception in MergeDataSet",e); //Puedes ver este log desde Logs en la consola de Catalyst
basicIO.setStatus(500);
}
}
}
Copia el código a continuación y pégalo en Mailer.java ubicado en el directorio functions/Mailer y guarda el archivo.
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"; //Ingresa la dirección de correo del remitente que configuraste anteriormente
@Override
public void runner(Context context, BasicIO basicIO) throws Exception {
try {
ZCProject.initProject();
Object content = basicIO.getArgument("content"); //Obtiene la lista final de la función MergeDataSet
Object mailId = basicIO.getArgument("mail_id"); //Obtiene la dirección de correo del usuario desde la entrada proporcionada
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); //Puedes ver este log desde Logs en la consola de Catalyst
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;
}
}
Instalar Express
Antes de codificar la función Node.js, debemos instalar las dependencias de Express Node.js en el directorio.
Para instalar Express.js en tu máquina local, navega al directorio de la función (functions/circuit) en tu terminal y ejecuta el siguiente comando:
Esto instalará el módulo Express y guardará las dependencias.
Esta información también se actualizará en el archivo package.json.
Ahora codifiquemos el archivo index.js.
Copia el código a continuación y pégalo en index.js ubicado en el directorio functions/circuit y guarda el archivo.
'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); //Proporciona el ID del circuito que crees en la consola
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); //Puedes ver este log desde Logs en la consola de Catalyst
res.status(500).send({ message: "Please try again after sometime!" });
})
});
module.exports = app;
Repasemos rápidamente las funciones que configuramos.
Circuit:
-
La función Advanced I/O circuit contiene una API /triggerCircuit que activa la ejecución del circuito que se configura en la consola de Catalyst.
Nota: Configuraremos el circuito después de desplegar los recursos del proyecto en la consola remota. -
La función circuit pasa los datos de entrada obtenidos del usuario final en la aplicación del cliente al circuito mientras activa su ejecución. Estos datos se pasan a la función del circuito por main.js en el directorio del cliente.
-
Después de que el circuito ha completado su ejecución, pasará un mensaje para mostrarse en la aplicación del cliente indicando al usuario que revise su dirección de correo electrónico para ver la lista de museos que satisfacen sus criterios. Este mensaje se configura en esta función.
RatingProcessor y TravellerTypeRatingProcessor:
- La función RatingProcessor almacena las siguientes calificaciones de los museos en un Java HashMap: Excellent, Very Good, Average, Poor, Terrible.
- La función TravellerTypeRatingProcessor almacena los siguientes tipos de viajero adecuados para los museos en un Java HashMap: Families, Couples, Solo, Business, Friends.
- Además de la calificación y el tipo de viajero, el usuario proporciona una entrada para el número de museos que desea que se listen en los resultados. Este valor se almacena en la variable count y es procesado por ambas funciones.
- Las funciones realizan llamadas a los conjuntos de datos traveller-rating.json o traveller-type-rating.json respectivamente, que están alojados por Catalyst. Estos conjuntos de datos contienen registros de calificaciones y tipo de viajero adecuado proporcionados por usuarios en varios sitios web.
- Los registros se obtienen de estos conjuntos de datos por ambas funciones, según la entrada proporcionada por el usuario. Por ejemplo, si el usuario seleccionó Excellent como el tipo de calificación, los museos con esa calificación se identifican en el conjunto de datos traveller-rating.json. Los museos con el mayor número de calificaciones Excellent, sin exceder el valor de conteo proporcionado por el usuario, se ordenan en orden descendente y se obtienen. Los registros que coinciden con la entrada de tipo de viajero proporcionada por el usuario también se obtienen de manera similar del conjunto de datos traveller-type-rating.json.
- Los registros obtenidos por ambas funciones se analizan como objetos JSON y se escriben en clases ObjectMapper. Luego se ordenan en una lista y se agregan a nuevos HashMaps en ambas funciones.
MergeDataSet:
- La función MergeDataSet obtiene los registros obtenidos por las funciones RatingProcessor y TravellerTypeRatingProcessor como argumentos.
- La función luego intersecta ambas listas y verifica los resultados de museos que están presentes en ambas listas.
- Luego agrega los museos que están presentes en ambas listas a una lista final y devuelve la lista como una respuesta JSON.
Mailer:
- La función Mailer obtiene la lista final de la función MergeDataSet en el circuito que configuraremos. Esto se establece como el contenido del correo. También obtiene la dirección de correo electrónico del usuario desde la entrada que proporcionan.
- Podemos configurar el asunto del correo y la dirección del remitente en la función. La función Mailer luego envía un correo electrónico a la dirección de correo del usuario con el contenido obtenido.
El directorio de funciones ahora está configurado.
Última actualización 2026-03-20 21:51:56 +0530 IST