Skip to content
Next Next commit
Sample client program/script to access read only data from Autonomous…
… Database Pre Authenticated Request URL
  • Loading branch information
sivankri committed Jun 28, 2024
commit 5bd052b419000f866a714c37ce3463d43402598c
224 changes: 224 additions & 0 deletions java/autonomous-db-parurl/AdbsParUrlClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/**
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or data
* (collectively the "Software"), free of charge and under any and all copyright
* rights in the Software, and any and all patent rights owned or freely
* licensable by each licensor hereunder covering either (i) the unmodified
* Software as contributed to or provided by such licensor, or (ii) the Larger
* Works (as defined below), to deal in both
*
* (a) the Software, and
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software (each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
* The above copyright notice and either this complete permission notice or at
* a minimum a reference to the UPL must be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.List;

/**
* This class provides a basic example of how to read the data from Autonomous Database pre-authenticated URL.
*
* <p>The example has some constraints. This is a single threaded example & cannot be used to fetch
* data from same AdbsParUrlExample class instance in multiple threads.
*
* <p>This example will do the following things:
*
* <ul>
* <li>Accepts Autonomous Database pre-authenticated URL as input.
* <li>Returns an iterator used to iterate records one by one.
* </ul>
*/
public class AdbsParUrlClient {
/**
* Pre Authenticated Request URL.
*/
private final String adbsParUrl;

/**
* Constructor
*
* @param adbsParUrl Pre Authenticated Request URL.
*/
public AdbsParUrlClient(String adbsParUrl) {
this.adbsParUrl = adbsParUrl;
}

/**
* Creates ResultSet object for iterating the results.
*
* @return ResultSet object for iterating the results.
* @throws IOException if fetching data from par url fails.
*/
public ResultSet execute() throws IOException {
final ResultSet resultSet = new ResultSet(this.adbsParUrl);
return resultSet;
}

/**
* Par Url Response pojo class
*/
@Getter
@Setter
@NoArgsConstructor
public static class ParUrlResponse {
private List<JsonNode> items;
private Boolean hasMore;
private long limit;
private long offset;
private long count;
private List<Link> links;

@Getter
@Setter
public static class Link {
private String rel;
private String href;
}
}

/**
* Helper class to iterate data fetched from the par url.
*/
public static class ResultSet {
private static final ObjectMapper mapper = new ObjectMapper();
private int currentOffset;
private ParUrlResponse parUrlResponse;

/**
* Constructor
*
* @param adbsParUrl Pre Authenticated Request URL.
* @throws IOException if fetching data from par url fails.
*/
public ResultSet(String adbsParUrl) throws IOException {
this.parUrlResponse = fetchData(adbsParUrl);
this.currentOffset = 0;
}

/**
* Method to fetch data from the par url.
*
* @param adbsParUrl Pre Authenticated Request URL.
* @return result pojo for the fetch par url data operation.
* @throws IOException
*/
private ParUrlResponse fetchData(String adbsParUrl) throws IOException {
final CloseableHttpClient httpClient = HttpClients.createDefault();
final HttpGet request = new HttpGet(adbsParUrl);
final HttpResponse response = httpClient.execute(request);
final int statusCode = response.getStatusLine().getStatusCode();

if (statusCode == HttpURLConnection.HTTP_OK) { // success
String responseStr = EntityUtils.toString(response.getEntity());
return mapper.readValue(responseStr, ParUrlResponse.class);
} else {
System.out.println(response.getStatusLine().toString());
throw new RuntimeException("Error while fetching data for the par Url.");
}

}

/**
* Helper method to check if more items are still available.
*
* @return true if available else false
*/
public boolean hasNext() {
return currentOffset < parUrlResponse.getCount() || (currentOffset == parUrlResponse.getCount() &&
BooleanUtils.isTrue(parUrlResponse.hasMore));
}

/**
* Helper method to return the next item from the cached list.
*
* @return next item from the cached data list.
* @throws IOException if fetching data from par url fails.
*/
public JsonNode next() throws IOException {
if (currentOffset < parUrlResponse.getCount()) {
return parUrlResponse.getItems().get(currentOffset++);
}

this.currentOffset = 0;
this.parUrlResponse = fetchData(getNextLink());
return parUrlResponse.getItems().get(currentOffset++);
}

/**
* Method to get the fetch link for the next page items.
*
* @return next page link.
*/
private String getNextLink() {
return parUrlResponse.links.stream()
.filter(l -> "next".equalsIgnoreCase(l.rel))
.map(l -> l.href)
.findFirst().get();
}
}

/**
* Fetch Data from par url sample main method.
*
* @param args input arguments
* @throws IOException if fetching data from par url fails.
*/
public static void main(String[] args) throws IOException {

/**
* Setting sample Adbs par url
*/
final String sampleAdbsParUrl = "https://dataaccess.adb.us-phoenix-1.oraclecloudapps.com/adb/p/NYGM5PicEMTe1hF.../data";

/**
* Initialize the class instance fetching par url data
*/
AdbsParUrlClient parUrlClient = new AdbsParUrlClient(sampleAdbsParUrl);
ResultSet rs = parUrlClient.execute();

/**
* Iterate the list until all records are returned.
*/
while (rs.hasNext()) {
JsonNode node = rs.next();
System.out.println(node);
}
}
}

5 changes: 5 additions & 0 deletions java/autonomous-db-parurl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Java Sample Accessing Read Only data from Autonomous Database Pre Authenticated Request URL.

This example java program provides the approach that consumers should be using to access read only data from Autonomous Database Pre Authenticated Request URL.

More details about the Autonomous Database Pre Authenticated Request URL can be found [here](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/autonomous-preauthenticated-request-url.html#GUID-976ABD3A-38A0-4E5E-BCA4-9FFB9A748C43).
113 changes: 113 additions & 0 deletions javascript/autonomous-db-parurl/AdbsParUrlClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
## Copyright (c) 2024 Oracle and/or its affiliates.
##
## The Universal Permissive License (UPL), Version 1.0
##
## Subject to the condition set forth below, permission is hereby granted to any
## person obtaining a copy of this software, associated documentation and/or data
## (collectively the "Software"), free of charge and under any and all copyright
## rights in the Software, and any and all patent rights owned or freely
## licensable by each licensor hereunder covering either (i) the unmodified
## Software as contributed to or provided by such licensor, or (ii) the Larger
## Works (as defined below), to deal in both
##
## (a) the Software, and
## (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
## one is included with the Software (each a "Larger Work" to which the Software
## is contributed by such licensors),
##
## without restriction, including without limitation the rights to copy, create
## derivative works of, display, perform, and distribute the Software and make,
## use, sell, offer for sale, import, export, have made, and have sold the
## Software and the Larger Work(s), and to sublicense the foregoing rights on
## either these or other terms.
##
## This license is subject to the following condition:
## The above copyright notice and either this complete permission notice or at
## a minimum a reference to the UPL must be included in all copies or
## substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
*/

/**
* This javascript class provides a basic interface example to read the data from Autonomous Database pre-authenticated URL.
*/
class AdbsParUrlClient {
constructor(parUrl) {
this.items = [];
this.totalRecords = 0;
this.collectionIndexPosition = 0;
this.nextGetParUrl = parUrl;
this.itemsSize = 0;
}

/**
* Return the next record from the cache for the Pre-auth request url.
*/
getNextItem() {
if (this.collectionIndexPosition < this.itemsSize) {
return this.items[this.collectionIndexPosition++];
} else if (this.nextGetParUrl == null) {
this.items = [];
this.collectionIndexPosition = 0;
this.nextGetParUrl = null;
this.itemsSize = 0;
return null;
} else {
this.items = [];
this.collectionIndexPosition = 0;
this.itemsSize = 0;
var jsonResponse = this.fetchParUrlData();
var hasMore = jsonResponse.hasMore;

console.log("items returned: " + jsonResponse.items.length);
this.totalRecords = this.totalRecords + jsonResponse.items.length;
this.itemsSize = jsonResponse.items.length;

for (var count = 0; count < jsonResponse.items.length; count++) {
this.items.push(jsonResponse.items[count]);
}

console.log("hasMore: " + hasMore);
if (hasMore) {
var links = jsonResponse.links;
for (var count = 0; count < links.length; count++) {
if (links[count]['rel'] == 'next') {
this.nextGetParUrl = links[count]['href'];
console.log("Next url href: " + this.nextGetParUrl);
}
}
} else {
this.nextGetParUrl = null;
}

return this.items[this.collectionIndexPosition++];
}
}

/**
* Fetch the Par Url data by invoking HTTP Get call.
*/
fetchParUrlData() {
console.log("Invoking Get call on Url: " + this.nextGetParUrl);
var request = new XMLHttpRequest();
request.open("GET", this.nextGetParUrl, false);
request.setRequestHeader("Content-Type", "application/json");
request.send();

console.log("Get Call status: " + request.status);

if (request.status === 200) {
return JSON.parse(request.responseText);
} else {
throw new Error("Failed to fetch the par url data");
}
}
}
Loading