[Progress News] [Progress OpenEdge ABL] Connecting to MongoDB from Corticon Using Service Callouts

Status
Not open for further replies.
B

Ben Blais

Guest
Learn how to create a working service callout that can read from and store to a MongoDB instance using Corticon's flexible datasource management API.

Progress Corticon 5.7 includes a unified datasource configuration file allowing users to configure connections to external sources of data. While this file is mostly used for connecting to external databases (either using ADC or EDC), it’s exposed in the service callout framework so users can connect Corticon Server to a customized datasource and handle the data appropriately even if the database isn’t natively supported. This guide explains how to connect to a MongoDB instance using a REST API.

Before starting, make sure you have all the prerequisite software:

  • Corticon Studio 5.7
  • Corticon Server 5.7 (for deployment)
  • MongoDB 3.6
  • MongoDB Compass (for setting up the database and catalog)
  • RESTHeart 3.2.2
Set Up MongoDB


Follow the instructions on the MongoDB website to install and start MongoDB. The website offers installation guides for all major desktop operating systems.

Open MongoDB Compass


The default connection settings should allow you to connect.



Create a Database and a Collection


Use “Corticon” as the name for both. (You don’t need to create a document; you’ll be doing that with the REST API).



Start RESTHeart

Step 1

Unzip the archive, open the containing directory and edit the etc/restheart.yml file with your favorite text editor. Make sure to configure the mongo-uri property to include the correct address and port of your MongoDB server. For example, if you’re running MongoDB locally on port 27017, change the following line from this:
mongo-uri: MongoDB://127.0.0.1



to this:

mongo-uri: MongoDB://127.0.0.1:27017



Step 2


Start RESTHeart, and you should see output like the following:

09:59:43.461 [main] INFO org.restheart.Bootstrapper - ANSI colored console: true
09:59:43.481 [main] INFO org.restheart.Bootstrapper - Starting RESTHeart instance default
09:59:43.483 [main] INFO org.restheart.Bootstrapper - version 3.2.2
09:59:43.486 [main] INFO org.restheart.Bootstrapper - Logging to file C:\Users\bblais\AppData\Local\Temp\\restheart.
log with level INFO
09:59:43.486 [main] INFO org.restheart.Bootstrapper - Logging to console with level INFO
09:59:44.229 [main] INFO org.restheart.Bootstrapper - MongoDB connection pool initialized
09:59:44.230 [main] INFO org.restheart.Bootstrapper - MongoDB version 3.6.2
09:59:44.230 [main] WARN org.restheart.Bootstrapper - ***** No Identity Manager specified. Authentication disabled.
09:59:44.231 [main] WARN org.restheart.Bootstrapper - ***** No access manager specified. users can do anything.
09:59:44.232 [main] INFO org.restheart.Bootstrapper - Authentication Mechanism io.undertow.security.impl.BasicAuthen
ticationMechanism enabled
09:59:44.232 [main] INFO org.restheart.Bootstrapper - Token based authentication enabled with token TTL 15 minutes
09:59:44.242 [main] INFO org.restheart.Bootstrapper - HTTPS listener bound at 0.0.0.0:4443
09:59:44.243 [main] INFO org.restheart.Bootstrapper - HTTP listener bound at 0.0.0.0:8080
09:59:44.244 [main] INFO org.restheart.Bootstrapper - Local cache for db and collection properties enabled with TTL
1000 msecs
09:59:44.245 [main] INFO org.restheart.Bootstrapper - Local cache for schema stores not enabled
09:59:44.423 [main] INFO org.restheart.Bootstrapper - URL / bound to MongoDB resource *
09:59:44.558 [main] INFO org.restheart.Bootstrapper - Embedded static resources browser extracted in C:\Users\bblais
\AppData\Local\Temp\restheart-


6229838428094629763
09:59:44.596 [main] INFO org.restheart.Bootstrapper - URL /browser bound to static resources C:\Users\bblais\AppData
\Local\Temp\restheart-6229838428094629763. Access Manager: false
09:59:44.790 [main] INFO org.restheart.Bootstrapper - RESTHeart started


Step 3


Test the endpoint using your favorite browser or HTTP client.



Now the REST API connected to MongoDB is up and running.

Create the Decision Service

Step 1


Open Corticon Studio and make a simple Vocabulary. You can follow this example of a mileage calculator. It will take in information about a car and calculate how many more miles it can drive before needing fuel.







Step 2


Create a Rulesheet to do the calculation.





Step 3


Make a Ruletest and add some sample data to ensure the Decision Service is working.





Step 4


Run the test and check your results.





Connect the Decision Service to Your MongoDB Instance Using a Service Callout

Step 1


Add an ADC configuration to your Vocabulary and choose any database type. (You won’t be using that for the service callout.)





Step 2


Replace the default URL with the path to the RESTHeart API and append the name of the document to the URL. In this example, the document name is “cars.”





Step 3


Create a service callout. As a shortcut, import the Corticon 5.7/Samples/Weather Callout file into your project; it already contains all the necessary libraries.





Step 4


After importing, delete the Java files and, optionally, rename the project.





Step 5


Write the code to create a class for your callout. Start by storing the data. (In this practice example, don’t worry too much about error handling.)

public static void storeData(ICcDataObjectManager dataObjectManager) throws Exception {


//

// Convert our DataObjects to JSON

//


//Since we are talking to a REST API convert the 'cars' to JSON

Set<ICcDataObject> cars = dataObjectManager.getEntitiesByName("Car");


//This will be the JSONObject we send

JSONObject carsJson = new JSONObject();


//And this will be the array we put all the 'cars' into

JSONArray carsArray = new JSONArray();


//Convert the data objects, each one will be a json object in the array

//Each attribute will be a property

for(ICcDataObject currentCar : cars) {

JSONObject currentCarJSON = new JSONObject();


//Get the attribute names

Set<String> attributeNames = currentCar.getAttributeNames();


//Loop through the attributes

for(String currentAttributeName : attributeNames) {

//Place the attribute value

currentCarJSON.put(currentAttributeName, currentCar.getAttributeValue(currentAttributeName));

}


//Add the new car JSON object to the array

carsArray.put(currentCarJSON);

}


//Place the array in the JSON object

carsJson.put("Cars", (Object)carsArray);



//

// Connect to MongoDB

//


//Get the datasource Manager

IDatasourceManager datasourceManager = dataObjectManager.getDatasourceManager();


//Get our MongoDB datasource

IDatasource mongoDBDatasource = datasourceManager.getDatasource("MongoDB");


//Open an http connection to the database

URL mongoDBConnectionURL = new URL(mongoDBDatasource.getDatasourceConnectionURL());

HttpURLConnection mongoDBConnection = (HttpURLConnection) mongoDBConnectionURL.openConnection();


//Since we are storing, we want to use the 'PUT' HTTP method

mongoDBConnection.setRequestMethod("PUT");


//Set the content type

mongoDBConnection.setRequestProperty("Content-Type", "application/json");


//Make sure we can write to the connection

mongoDBConnection.setDoOutput(true);


//We are going to write the data to the connection output stream

BufferedWriter jsonContentWriter = null;

try {

jsonContentWriter = new BufferedWriter(new OutputStreamWriter(mongoDBConnection.getOutputStream()));


//Convert our JSON to a string to send to the REST API

jsonContentWriter.write(carsJson.toString());


//Flush the stream

jsonContentWriter.flush();


//Open the connection

mongoDBConnection.connect();


//Print out a rule message on success or failure

int mongoDBResponseCode = mongoDBConnection.getResponseCode();


if(mongoDBResponseCode >= 200 && mongoDBResponseCode < 300) {

dataObjectManager.postMessage(ICcDataObjectManager.INFO, "MongoDB PUT call SUCCEEDED with a status of " + Integer.toString(mongoDBResponseCode), null);

} else {

dataObjectManager.postMessage(ICcDataObjectManager.INFO, "MongoDB PUT call FAILED with a status of " + Integer.toString(mongoDBResponseCode), null);

}

} finally {

//Close the stream and connection once we are done

if(jsonContentWriter != null) {

jsonContentWriter.close();

}

mongoDBConnection.disconnect();

}


}



Export the JAR File and Test the New Service Callout

Step 1


To export the JAR file, right-click on the project, select Export in the menu and select Java/JAR File from the wizard options.





Step 2


Add the exported JAR to the project.





Step 3


Create a Ruleflow to test the new service callout.





Step 4


Make a new Testsheet in the Ruletest and select the Ruleflow as the test subject.





Step 5


Run the test.



If you successfully hit the REST API, you should see the new document populated with data.



Now, you have stored data in MongoDB.



Retrieve Data from MongoDB

Step 1


Go back to the service callout and update it to read the information from the REST API instead of storing it.

Step 2


Add the following method to your service callout.

public static void readData(ICcDataObjectManager dataObjectManager) throws Exception {


//This will be the object that holds the JSON response from the rest API

JSONObject mongoDBCarDocument = null;


//

// Connect to MongoDB

//


//Get the datasource Manager

IDatasourceManager datasourceManager = dataObjectManager.getDatasourceManager();


//Get our MongoDB datasource

IDatasource mongoDBDatasource = datasourceManager.getDatasource("MongoDB");


//Open an http connection to the database

URL mongoDBConnectionURL = new URL(mongoDBDatasource.getDatasourceConnectionURL());

HttpURLConnection mongoDBConnection = (HttpURLConnection) mongoDBConnectionURL.openConnection();


//Since we are reading, we want to use the 'GET' HTTP method

mongoDBConnection.setRequestMethod("GET");


//Set the content type

mongoDBConnection.setRequestProperty("Content-Type", "application/json");


//Make the connection

mongoDBConnection.connect();


//Print out a rule message on success or failure

int mongoDBResponseCode = mongoDBConnection.getResponseCode();


if(mongoDBResponseCode >= 200 && mongoDBResponseCode < 300) {

dataObjectManager.postMessage(ICcDataObjectManager.INFO, "MongoDB GET call SUCCEEDED with a status of " + Integer.toString(mongoDBResponseCode), null);

} else {

dataObjectManager.postMessage(ICcDataObjectManager.INFO, "MongoDB GET call FAILED with a status of " + Integer.toString(mongoDBResponseCode), null);

}


//Read response data

BufferedReader jsonContentReader = null;

try {

jsonContentReader = new BufferedReader(new InputStreamReader(mongoDBConnection.getInputStream()));


//Get all the data from the stream

StringBuilder jsonResultStringBuilder = new StringBuilder();


//Read each line of the input to the end

String lineOfJson = null;

while( (lineOfJson = jsonContentReader.readLine()) != null) {

jsonResultStringBuilder.append(lineOfJson);

}


//Convert the entire message payload into a JSONObject

mongoDBCarDocument = new JSONObject(jsonResultStringBuilder.toString());


} finally {

if(jsonContentReader != null) {

jsonContentReader.close();

}

mongoDBConnection.disconnect();

}


//

// Convert our JSON to DataObjects

//


//Get the 'cars' array out of the Document

JSONArray carsJsonArray = mongoDBCarDocument.getJSONArray("Cars");


//Create a data object based off of each car in the array.

for(int carsIndex = 0; carsIndex < carsJsonArray.length(); carsIndex++) {

//Get the JSONObject out of the array

JSONObject currentCar = carsJsonArray.getJSONObject(carsIndex);


//Create the ICcDataObject

ICcDataObject carDataObject = dataObjectManager.createEntity("Car");


Set<String> attributeNames = carDataObject.getAttributeNames();


//Loop through the data object attributes and, if they are properties in the JSONObject, set them

for(String currentAttributeName : attributeNames) {

if(currentCar.has(currentAttributeName)) {


//Get the attribute's type

String currentAttributeType = carDataObject.getAttributeDataType(currentAttributeName);


//Create a variable for storing the attribute value in

Object currentAttributeValue = null;


//Long

if(currentAttributeType.contains("Long")) {

currentAttributeValue = new Long(currentCar.getLong(currentAttributeName));

}

//BigDecimal

else if(currentAttributeType.contains("BigDecimal")) {

currentAttributeValue = new BigDecimal(currentCar.getLong(currentAttributeName));

}

//Integer

else if(currentAttributeType.contains("Integer")) {

currentAttributeValue = new Integer(currentCar.getInt(currentAttributeName));

}

//String

else {

currentAttributeValue = currentCar.getString(currentAttributeName);

}


carDataObject.setAttributeValue(currentAttributeName, currentAttributeValue);

}

}

}

}



Step 3


Export the JAR file again and restart Corticon Studio.

Step 4


Create a new Ruleflow to handle retrieval from the database. Put the calculator Rulesheet in the Ruleflow to use the data retrieved from the database.





Step 5


Add a new Testsheet with the new Ruleflow as test subject to try out the new service. Run the test.



Step 6


If the retrieval succeeds, bring everything together by adding the first service callout, which saves information to the database, to the Ruleflow.



Step 7


Test again.



Step 8


Hit the API and see the updated MilesTillEmpty property.



That’s It!


With that, we're done with this example. If you’re feeling adventurous, you can also export the datasource configuration file and build a Decision Service for deploying to the server. Now, you know how to create a working service callout that can read from and store to a MongoDB instance using Corticon. And you can use this approach to create interesting and useful callouts with Corticon’s flexible datasource management API.

This is just one of many new improvements we’ve delivered with Corticon 5.7. Check out everything that’s new in this release, then contact us to schedule a demo and let us know what you think.

Continue reading...
 
Status
Not open for further replies.
Top