--- title: "Configurar las funciones" url: https://docs.catalyst.zoho.com/es/tutorials/museum-finder/configure-functions/ description: "Construye una aplicación web Museum Finder usando Catalyst Functions que te ayuda a encontrar museos según criterios de calificaciones y tipo de viajero, y automatiza su flujo de trabajo usando Catalyst Circuits." last_updated: 2026-03-20T16:21:56Z service: All Services type: tutorial related_links: - name: "Basic I/O Functions" url: /es/serverless/help/functions/basic-io/ - name: "Advanced I/O Functions" url: /es/serverless/help/functions/advanced-io/ - name: "Functions Directory Structure" url: /es/cli/v1/project-directory-structure/functions-directory --- # 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](https://docs.catalyst.zoho.com/es/cli/v1/project-directory-structure/functions-directory) 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](https://docs.npmjs.com/files/package.json)` y `[package-lock.json](https://docs.npmjs.com/configuring-npm/package-lock-json.html)` 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. > **Nota:** Por favor revisa el código en esta sección para asegurarte de comprenderlo completamente. Discutiremos el código de las funciones al final de la sección. Copia el código a continuación y pégalo en `RatingProcessor.java` ubicado en el directorio `functions/RatingProcessor` y guarda el archivo. **RatingProcessor.java** ```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) { // 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. **TravellerTypeRatingProcessor.java** ```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); //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. **MergeDataSet.java** ```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()); //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. **Mailer.java** ```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"; //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; } } ``` > **Nota:** Proporciona la dirección de correo electrónico del remitente que configuraste anteriormente, en la línea 19. #### Instalar Express Antes de codificar la función Node.js, debemos instalar las dependencias de [Express Node.js](https://expressjs.com/) 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: ```sh npm install express --save ``` 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. **index.js** ```javascript '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; ``` > **Nota:** Después de crear el circuito en la consola de Catalyst, asegúrate de proporcionar el ID del circuito en esta función en la línea 14. 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](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html): `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.