Like what you see? Have a play with our trial version.

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
[
  { "itemIndex": 0, "optionKey": "SKIP", "optionValue": false },
  { "itemIndex": 0, "optionKey": "OPTION\", "optionValue": "ADD" }
]

...

Code Block
languagejava
titleJava
collapsetrue
package rest.code.examples;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Random;
import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * Import a datasource for a client org using the Yellowfin REST API
 */
public class ImportDatasourceForClientOrg {
    public static void main(String[] args) throws Exception {

        System.out.print("Import Datasource for Client");

        String host = "http://localhost:8080/Yellowfin";
        String restUsername = "admin@yellowfin.com.au";
        String restPassword = "test";

        String tenantClientReferenceId = "NEWCLIENT";
        String databaseUserName = "postgres";
        String encryptedPassword = "NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw";
        String serverAddress = "localhost";
        String databaseName = "testdata";

        String token = generateTokenForTenant(host, restUsername, restPassword, tenantClientReferenceId);

        Integer tenantId = retrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId);
        System.out.println("Tenant Id: " + tenantId);

        // Replace tokens with values
        String modifiedFileContents = importFileContents;
        modifiedFileContents = modifiedFileContents.replace("[USERNAME]", databaseUserName);
        modifiedFileContents = modifiedFileContents.replace("[TENANT_NAME]", tenantClientReferenceId);
        modifiedFileContents = modifiedFileContents.replace("[ENCRYPTED_PASSWORD]", encryptedPassword);
        modifiedFileContents = modifiedFileContents.replace("[SERVER_ADDRESS]", serverAddress);
        modifiedFileContents = modifiedFileContents.replace("[DATABASE_NAME]", databaseName);

        HttpEntity multipartEntity = MultipartEntityBuilder
                .create()
                .setMode(HttpMultipartMode.LEGACY)
                .setCharset(Charset.forName("UTF-8"))
                .addBinaryBody("contentToProcess", modifiedFileContents.getBytes("UTF-8"), ContentType.DEFAULT_BINARY, "YFExport.xml")
                .addTextBody("importOptions", "[{ \"itemIndex\": 0, \"optionKey\": \"SKIP\", \"optionValue\": false }, { \"itemIndex\": 0, \"optionKey\": \"OPTION\", \"optionValue\": \"ADD\" }]", ContentType.APPLICATION_JSON)
                .build();

        System.out.println("Content-Type: " + multipartEntity.getContentType());
        Content c = Request.post(host + "/api/rpc/import-export/import-content")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + token)
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", multipartEntity.getContentType())
                .addHeader("cache-control", "no-cache")
                .body(multipartEntity)
                .execute()
                .returnContent();

        System.out.println(c.asString());

    }
    /*
     *  This function fetches a client organization's integer id for a given clientRefCode
     */

    public static Integer retrieveTenantIpIdForTenantName(String host, String token, String tenantCode) throws IOException {

        Content c = Request.get(host + "/api/orgs")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + token)
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .execute().returnContent();

        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement groupList = jsonObject.get("items");
        JsonArray groups = groupList.getAsJsonArray();

        for (int i=0; i < groups.size(); i++ ) {
            JsonObject group = groups.getAsJsonArray().get(i).getAsJsonObject();
            if (!group.has("clientRefId")) continue;
            if (tenantCode.equals(group.get("clientRefId").getAsString())) return group.get("ipOrg").getAsInt();
        }

        System.out.println("Tenant could not be found for code:" + tenantCode);
        System.exit(-1);

        return null;
    }


    /*
     *  This function generates an access token for a user that will grant them access to
     *  call REST API endpoints.
     */

    public static String generateTokenForTenant(String host, String username, String password, String tenant) throws IOException {

        Content c = Request.post(host + "/api/refresh-tokens")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong())
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .bodyString("{ \"userName\": \""+ username + "\",\"password\": \""+ password + "\", \"clientOrgRef\": \"" + tenant + "\"}", null)
                .execute().returnContent();

        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject("_embedded").getAsJsonObject("accessToken").get("securityToken");

        if (accessToken!=null) {
            System.out.println("Access Token: " + accessToken);
        } else {
            System.out.println("Token not retrieved successfully");
            System.exit(-1);
        }
        return accessToken.getAsString();

    }
    private static String importFileContents = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) --><data>\n"
            + "  <info>\n"
            + "    <exportversion>4</exportversion>\n"
            + "    <exportsubversion>54</exportsubversion>\n"
            + "    <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>\n"
            + "    <appversion>9.11</appversion>\n"
            + "    <appsubversion>0.3</appsubversion>\n"
            + "    <buildversion>20240607</buildversion>\n"
            + "    <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>\n"
            + "    <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>\n"
            + "  </info>\n"
            + "  <source>\n"
            + "    <id>132641</id>\n"
            + "    <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>\n"
            + "    <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>\n"
            + "    <databasePath>public</databasePath>\n"
            + "    <userName>[USERNAME]</userName>\n"
            + "    <password>[ENCRYPTED_PASSWORD]</password>\n"
            + "    <connectionTypeCode>GENERICUSER</connectionTypeCode>\n"
            + "    <connectionMethodCode>JDBC</connectionMethodCode>\n"
            + "    <connectionDriver>org.postgresql.Driver</connectionDriver>\n"
            + "    <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>\n"
            + "    <databaseTypeCode>POSTGRESQL</databaseTypeCode>\n"
            + "    <minConnections>1</minConnections>\n"
            + "    <maxConnections>5</maxConnections>\n"
            + "    <connectionRefreshTime>180</connectionRefreshTime>\n"
            + "    <connectionTimeOut>180</connectionTimeOut>\n"
            + "    <accessCode>UNSECURE</accessCode>\n"
            + "    <maxRowCount>10000</maxRowCount>\n"
            + "    <maxAnalysisRowCount>0</maxAnalysisRowCount>\n"
            + "    <broadcastPermitted>true</broadcastPermitted>\n"
            + "    <subscribePermitted>true</subscribePermitted>\n"
            + "    <dataProfileEnabled>true</dataProfileEnabled>\n"
            + "    <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>\n"
            + "    <secondaryMinConnections>0</secondaryMinConnections>\n"
            + "    <secondaryMaxConnections>0</secondaryMaxConnections>\n"
            + "    <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>\n"
            + "    <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>\n"
            + "    <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>\n"
            + "    <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>\n"
            + "    <filterList/>\n"
            + "    <sourceParameterList>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>DATABASE</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue>[DATABASE_NAME]</parameterValue>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>true</userVisible>\n"
            + "      </sourceParameter>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>HOSTNAME</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue>[SERVER_ADDRESS]</parameterValue>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>true</userVisible>\n"
            + "      </sourceParameter>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>ISOLATIONLEVEL</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue/>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>true</userVisible>\n"
            + "      </sourceParameter>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>PORT</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue>5432</parameterValue>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>true</userVisible>\n"
            + "      </sourceParameter>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>SOURCECLASSNAME</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>false</userVisible>\n"
            + "      </sourceParameter>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>USESCHEMA</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue>true</parameterValue>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>true</userVisible>\n"
            + "      </sourceParameter>\n"
            + "      <sourceParameter>\n"
            + "        <id>0</id>\n"
            + "        <parameterTypeCode>TEXT</parameterTypeCode>\n"
            + "        <parameterKey>YF_DRIVER_SELECTION</parameterKey>\n"
            + "        <parameterIndex>0</parameterIndex>\n"
            + "        <parameterValue>org.postgresql.Driver</parameterValue>\n"
            + "        <documentId>0</documentId>\n"
            + "        <userVisible>true</userVisible>\n"
            + "      </sourceParameter>\n"
            + "    </sourceParameterList>\n"
            + "  </source>\n"
            + "  <translationDictionary/>\n"
            + "  <refCodeDictionary/>\n"
            + "</data>";
}
Code Block
languagec#
titleC#
collapsetrue
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace YellowfinAPIExamples
{
    public class ImportDatasourceForClientOrg
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Import Datasource for Client");

            string host = "http://localhost:8080/Yellowfin";
            string restUsername = "admin@yellowfin.com.au";
            string restPassword = "test";

            string tenantClientReferenceId = "NEWCLIENT";
            string databaseUserName = "postgres";
            string encryptedPassword = "NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw";
            string serverAddress = "localhost";
            string databaseName = "testdata";

            string token = await GenerateTokenForTenant(host, restUsername, restPassword, tenantClientReferenceId);

            int tenantId = await RetrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId);
            Console.WriteLine("Tenant Id: " + tenantId);

            // Replace tokens with values
            string modifiedFileContents = ImportFileContents;
            modifiedFileContents = modifiedFileContents.Replace("[USERNAME]", databaseUserName)
                .Replace("[TENANT_NAME]", tenantClientReferenceId)
                .Replace("[ENCRYPTED_PASSWORD]", encryptedPassword)
                .Replace("[SERVER_ADDRESS]", serverAddress)
                .Replace("[DATABASE_NAME]", databaseName);

            using (var httpClient = new HttpClient())
            {
                var content = new MultipartFormDataContent
                {
                    {
                        new ByteArrayContent(Encoding.UTF8.GetBytes(modifiedFileContents)), "contentToProcess",
                        "YFExport.xml"
                    },
                    {
                        new StringContent(
                            "[{ \"itemIndex\": 0, \"optionKey\": \"SKIP\", \"optionValue\": false }, { \"itemIndex\": 0, \"optionKey\": \"OPTION\", \"optionValue\": \"ADD\" }]",
                            Encoding.UTF8, "application/json"),
                        "importOptions"
                    }
                };

                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("YELLOWFIN",
                    "ts=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + " , nonce=" + new Random().NextInt64() +
                    ", token=" + token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/vnd.yellowfin.api-v1+json"));
                httpClient.DefaultRequestHeaders.Add("cache-control", "no-cache");

                HttpResponseMessage response =
                    await httpClient.PostAsync(host + "/api/rpc/import-export/import-content", content);
                string responseBody = await response.Content.ReadAsStringAsync();
                Console.WriteLine(responseBody);
            }
        }

        private static async Task<int> RetrieveTenantIpIdForTenantName(string host, string token, string tenantCode)
        {
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("YELLOWFIN",
                    "ts=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + " , nonce=" + new Random().NextInt64() +
                    ", token=" + token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/vnd.yellowfin.api-v1+json"));

                HttpResponseMessage response = await httpClient.GetAsync(host + "/api/orgs");
                string responseBody = await response.Content.ReadAsStringAsync();

                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseBody);
                JArray groups = (JArray)jsonObject["items"];

                foreach (var group in groups)
                {
                    if (group["clientRefId"] != null && tenantCode == group["clientRefId"].ToString())
                    {
                        return (int)group["ipOrg"];
                    }
                }

                Console.WriteLine("Tenant could not be found for code:" + tenantCode);
                Environment.Exit(-1);
                return 0;
            }
        }

        private static async Task<string> GenerateTokenForTenant(string host, string username, string password,
            string tenant)
        {
            using (var client = new HttpClient())
            {
                var request = new HttpRequestMessage(HttpMethod.Post, host + "/api/refresh-tokens");
                request.Headers.Add("Authorization",
                    "YELLOWFIN ts=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + ", nonce=" +
                    new Random().NextInt64());
                request.Headers.Add("Accept", "application/vnd.yellowfin.api-v1+json");
                request.Content = new StringContent(
                    JsonConvert.SerializeObject(new
                        { userName = username, password = password, clientOrgRef = tenant }),
                    Encoding.UTF8,
                    "application/json"
                );

                HttpResponseMessage response = await client.SendAsync(request);
                string responseContent = await response.Content.ReadAsStringAsync();

                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseContent);
                string accessToken = jsonObject["_embedded"]["accessToken"]["securityToken"].ToString();

                if (!string.IsNullOrEmpty(accessToken))
                {
                    Console.WriteLine("Access Token: " + accessToken);
                }
                else
                {
                    Console.WriteLine("Token not retrieved");
                    Environment.Exit(-1);
                }

                return accessToken;
            }
        }

        private static readonly string ImportFileContents =
            @"<?xml version=""1.0"" encoding=""UTF-8""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) --><data>
              <info>
                <exportversion>4</exportversion>
                <exportsubversion>54</exportsubversion>
                <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
                <appversion>9.11</appversion>
                <appsubversion>0.3</appsubversion>
                <buildversion>20240607</buildversion>
                <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
                <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
              </info>
              <source>
                <id>132641</id>
                <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
                <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
                <databasePath>public</databasePath>
                <userName>[USERNAME]</userName>
                <password>[ENCRYPTED_PASSWORD]</password>
                <connectionTypeCode>GENERICUSER</connectionTypeCode>
                <connectionMethodCode>JDBC</connectionMethodCode>
                <connectionDriver>org.postgresql.Driver</connectionDriver>
                <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
                <databaseTypeCode>POSTGRESQL</databaseTypeCode>
                <minConnections>1</minConnections>
                <maxConnections>5</maxConnections>
                <connectionRefreshTime>180</connectionRefreshTime>
                <connectionTimeOut>180</connectionTimeOut>
                <accessCode>UNSECURE</accessCode>
                <maxRowCount>10000</maxRowCount>
                <maxAnalysisRowCount>0</maxAnalysisRowCount>
                <broadcastPermitted>true</broadcastPermitted>
                <subscribePermitted>true</subscribePermitted>
                <dataProfileEnabled>true</dataProfileEnabled>
                <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
                <secondaryMinConnections>0</secondaryMinConnections>
                <secondaryMaxConnections>0</secondaryMaxConnections>
                <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
                <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
                <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
                <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
                <filterList/>
                <sourceParameterList>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>DATABASE</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[DATABASE_NAME]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>HOSTNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[SERVER_ADDRESS]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>ISOLATIONLEVEL</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue/>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>PORT</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>5432</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>SOURCECLASSNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>false</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>USESCHEMA</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>true</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>YF_DRIVER_SELECTION</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>org.postgresql.Driver</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                </sourceParameterList>
              </source>
              <translationDictionary/>
              <refCodeDictionary/>
            </data>";
    }
}
Code Block
titleGo
collapsetrue
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math/rand"
    "mime/multipart"
    "net/http"
    "strings"
    "time"
)

func main() {
	host := "http://localhost:8080/Yellowfin"
    restUsername := "admin@yellowfin.com.au"
    restPassword := "test"

    tenantClientReferenceId := "NEWCLIENT"
    databaseUserName := "postgres"
    encryptedPassword := "NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw"
    serverAddress := "localhost"
    databaseName := "testdata"

    token, err := generateToken(host, restUsername, restPassword, tenantClientReferenceId)
	if err != nil {
		fmt.Println("Error generating token:", err)
		return
	}

	tenantId, err := retrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId)
	if err != nil {
		fmt.Println("Error retrieving tenant ID:", err)
		return
	}
	fmt.Println("Tenant Id:", tenantId)

	// Replace tokens with values
	modifiedFileContents := strings.Replace(importFileContents, "[USERNAME]", databaseUserName, -1)
	modifiedFileContents = strings.Replace(modifiedFileContents, "[TENANT_NAME]", tenantClientReferenceId, -1)
	modifiedFileContents = strings.Replace(modifiedFileContents, "[ENCRYPTED_PASSWORD]", encryptedPassword, -1)
	modifiedFileContents = strings.Replace(modifiedFileContents, "[SERVER_ADDRESS]", serverAddress, -1)
	modifiedFileContents = strings.Replace(modifiedFileContents, "[DATABASE_NAME]", databaseName, -1)

	bodyBuffer := &bytes.Buffer{}
	writer := multipart.NewWriter(bodyBuffer)

	// Add file content
	part, err := writer.CreateFormFile("contentToProcess", "YFExport.xml")
	if err != nil {
		fmt.Println("Error creating form file:", err)
		return
	}
	part.Write([]byte(modifiedFileContents))

	// Add text body
	err = writer.WriteField("importOptions", `[{"itemIndex": 0, "optionKey": "SKIP", "optionValue": false}, {"itemIndex": 0, "optionKey": "OPTION", "optionValue": "ADD"}]`)
	if err != nil {
		fmt.Println("Error writing field:", err)
		return
	}

	writer.Close()

	client := &http.Client{}
	req, err := http.NewRequest("POST", host+"/api/rpc/import-export/import-content", bodyBuffer)
	if err != nil {
		fmt.Println("Error creating request:", err)
		return
	}

	nonce := rand.Int63()

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d, token=%s", time.Now().UnixMilli(), nonce, token))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", writer.FormDataContentType())
	req.Header.Set("cache-control", "no-cache")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}

	fmt.Println(string(body))
}

func generateToken(host, restUsername, restPassword, tenant string) (string, error) {
	nonce := rand.Int63()

	requestBody, err := json.Marshal(map[string]string{
        "userName":     restUsername,
        "password":     restPassword,
        "clientOrgRef": tenant,
	})
	if err != nil {
		fmt.Println("Error marshaling request body:", err)
		return "", err
	}

	client := &http.Client{}
	request, err := http.NewRequest("POST", host+"/api/refresh-tokens", bytes.NewBuffer(requestBody))
	if err != nil {
		fmt.Println("Error creating request:", err)
		return "", err
	}

	request.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d", time.Now().UnixMilli(), nonce))
	request.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	request.Header.Set("Content-Type", "application/json")

	response, err := client.Do(request)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return "", err
	}
	defer response.Body.Close()

	responseBody, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return "", err
	}

	var jsonResponse map[string]interface{}
	err = json.Unmarshal(responseBody, &jsonResponse)
	if err != nil {
		fmt.Println("Error parsing JSON response:", err)
		return "", err
	}

	accessToken, ok := jsonResponse["_embedded"].(map[string]interface{})["accessToken"].(map[string]interface{})["securityToken"].(string)
	if !ok {
		fmt.Println("Token not retrieved")
		return "", fmt.Errorf("Token not retrieved successfully")
	}

	return accessToken, nil
}

func retrieveTenantIpIdForTenantName(host, token, tenantCode string) (int, error) {
	client := &http.Client{}
	req, err := http.NewRequest("GET", host+"/api/orgs", nil)
	if err != nil {
		return 0, err
	}

	nonce := rand.Int63()

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d, token=%s", time.Now().UnixMilli(), nonce, token))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	var jsonResponse map[string]interface{}
	err = json.Unmarshal(body, &jsonResponse)
	if err != nil {
		return 0, err
	}

	items, ok := jsonResponse["items"].([]interface{})
	if !ok {
		return 0, fmt.Errorf("Invalid response format")
	}

	for _, item := range items {
		group, ok := item.(map[string]interface{})
		if !ok {
			continue
		}

		if group["clientRefId"] == tenantCode {
			return int(group["ipOrg"].(float64)), nil
		}
	}

	return 0, fmt.Errorf("Tenant could not be found for code: %s", tenantCode)
}

const importFileContents = `<?xml version="1.0" encoding="UTF-8"?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) --><data>
              <info>
                <exportversion>4</exportversion>
                <exportsubversion>54</exportsubversion>
                <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
                <appversion>9.11</appversion>
                <appsubversion>0.3</appsubversion>
                <buildversion>20240607</buildversion>
                <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
                <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
              </info>
              <source>
                <id>132641</id>
                <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
                <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
                <databasePath>public</databasePath>
                <userName>[USERNAME]</userName>
                <password>[ENCRYPTED_PASSWORD]</password>
                <connectionTypeCode>GENERICUSER</connectionTypeCode>
                <connectionMethodCode>JDBC</connectionMethodCode>
                <connectionDriver>org.postgresql.Driver</connectionDriver>
                <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
                <databaseTypeCode>POSTGRESQL</databaseTypeCode>
                <minConnections>1</minConnections>
                <maxConnections>5</maxConnections>
                <connectionRefreshTime>180</connectionRefreshTime>
                <connectionTimeOut>180</connectionTimeOut>
                <accessCode>UNSECURE</accessCode>
                <maxRowCount>10000</maxRowCount>
                <maxAnalysisRowCount>0</maxAnalysisRowCount>
                <broadcastPermitted>true</broadcastPermitted>
                <subscribePermitted>true</subscribePermitted>
                <dataProfileEnabled>true</dataProfileEnabled>
                <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
                <secondaryMinConnections>0</secondaryMinConnections>
                <secondaryMaxConnections>0</secondaryMaxConnections>
                <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
                <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
                <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
                <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
                <filterList/>
                <sourceParameterList>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>DATABASE</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[DATABASE_NAME]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>HOSTNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[SERVER_ADDRESS]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>ISOLATIONLEVEL</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue/>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>PORT</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>5432</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>SOURCECLASSNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>false</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>USESCHEMA</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>true</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>YF_DRIVER_SELECTION</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>org.postgresql.Driver</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                </sourceParameterList>
              </source>
              <translationDictionary/>
              <refCodeDictionary/>
            </data>
`

...

Code Block
languagejava
titleJava
collapsetrue
package rest.code.examples;
import java.io.IOException;
import java.util.Random;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* Create a datasource using the Yellowfin REST API
*/
public class CreateADataSource {
   public static void main(String[] args) throws Exception {
     
	    	String host = "http://localhost:8080/yellowfinHead";
	    	String restUsername = "admin@yellowfin.com.au";
	    	String restPassword = "test";
	    	
	    	String createDataSourcePayload = "{\n"
                    + "   \"sourceName\": \"PostgreSQL Database Created Via Import\",\n"
                    + "   \"sourceDescription\": \"\",\n"
                    + "   \"sourceType\": \"POSTGRESQL\",\n"
                    + "   \"connectionType\": \"JDBC\",\n"
                    + "   \"connectionTypeCode\": \"GENERICUSER\",\n"
                    + "   \"connectionDriver\": \"org.postgresql.Driver\",\n"
                    + "   \"connectionString\": \"jdbc:postgresql://192.168.1.100:5432/testdata\",\n"
                    + "   \"connectionTimeout\": 180,\n"
                    + "   \"userName\": \"postgres\",\n"
                    + "   \"minimumConnections\": 1,\n"
                    + "   \"maximumConnections\": 5,\n"
                    + "   \"refreshTime\": 180,\n"
                    + "   \"timezone\": \"AUSTRALIA/SYDNEY\",\n"
                    + "   \"accessLevelCode\": \"UNSECURE\",\n"
                    + "   \"maxRows\": 10000,\n"
                    + "   \"maxAnalysisRows\": 0,\n"
                    + "   \"inheritChildSourceFilters\": false,\n"
                    + "   \"sourceLogIndicator\": false,\n"
                    + "   \"sourceOptions\": [\n"
                    + "{\n"
                    + "\"optionKey\": \"ISOLATIONLEVEL\",\n"
                    + "\"optionValue\": \"1.0\",\n"
                    + "\"valueDataType\": \"1\"\n"
                    + "},\n"
                    + "{\n"
                    + "\"optionKey\": \"USESCHEMA\",\n"
                    + "\"optionValue\": \"true\",\n"
                    + "\"valueDataType\": \"6\"\n"
                    + "},\n"
                    + "{\n"
                    + "\"optionKey\": \"HOSTNAME\",\n"
                    + "\"optionValue\": \"192.168.1.100\",\n"
                    + "\"valueDataType\": \"2\"\n"
                    + "},\n"
                    + "{\n"
                    + "\"optionKey\": \"PORT\",\n"
                    + "\"optionValue\": \"5432\",\n"
                    + "\"valueDataType\": \"1\"\n"
                    + "},\n"
                    + "{\n"
                    + "\"optionKey\": \"DATABASE\",\n"
                    + "\"optionValue\": \"testdata\",\n"
                    + "\"valueDataType\": \"2\"\n"
                    + "},\n"
                    + "{\n"
                    + "\"optionKey\": \"YF_DRIVER_SELECTION\",\n"
                    + "\"optionValue\": \"org.postgresql.Driver\",\n"
                    + "\"valueDataType\": \"2\"\n"
                    + "}\n"
                    + "    ]\n"
                    + "}"
                    ;
	    							  
	    			
	    	
	    	
	    	String token = generateToken(host, restUsername, restPassword);
	    	
	    	System.out.println("Payload: " + createDataSourcePayload);
	    	
	    	Content c = Request.post(host + "/api/data-sources")
	  	    		.addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + token)
	  	    		.addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
	  	    		.addHeader("Content-Type", "application/json")
	  	    		.bodyString(createDataSourcePayload, null)
	  	        .execute().returnContent();
	  	    	
	    System.out.print(c.asString());
	 
   }
  
   public static String generateToken(String host, String username, String password) throws IOException {
   	
   	  	Content c = Request.post(host + "/api/refresh-tokens")
 	    		.addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong())
 	    		.addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
 	    		.addHeader("Content-Type", "application/json")
 	    		.bodyString("{ \"userName\": \""+ username + "\",\"password\": \""+ password + "\"}", null)
 	        .execute().returnContent();
 	    	
 	    JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
 	    JsonElement accessToken = jsonObject.getAsJsonObject("_embedded").getAsJsonObject("accessToken").get("securityToken");
 	   
 	    if (accessToken!=null) {
 	    		System.out.println("Access Token: " + accessToken);
 	    } else {
 	    		System.out.println("Token not retrieved successfully");
 	    		System.exit(-1);
 	    }
 	    return accessToken.getAsString();
   	
   }
  
}
Code Block
languagec#
titleC#
collapsetrue
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace YellowfinAPIExamples
{
    public class CreateADataSource
    {
        static async Task Main(string[] args)
        {
            string host = "http://localhost:8080/Yellowfin";
            string restUsername = "admin@yellowfin.com.au";
            string restPassword = "test";

            string createDataSourcePayload = @"
{
    ""sourceName"": ""PostgreSQL Database Created Via Import"",
    ""sourceDescription"": """",
    ""sourceType"": ""POSTGRESQL"",
    ""connectionType"": ""JDBC"",
    ""connectionTypeCode"": ""GENERICUSER"",
    ""connectionDriver"": ""org.postgresql.Driver"",
    ""connectionString"": ""jdbc:postgresql://192.168.1.100:5432/testdata"",
    ""connectionTimeout"": 180,
    ""userName"": ""postgres"",
    ""minimumConnections"": 1,
    ""maximumConnections"": 5,
    ""refreshTime"": 180,
    ""timezone"": ""AUSTRALIA/SYDNEY"",
    ""accessLevelCode"": ""UNSECURE"",
    ""maxRows"": 10000,
    ""maxAnalysisRows"": 0,
    ""inheritChildSourceFilters"": false,
    ""sourceLogIndicator"": false,
    ""sourceOptions"": [
        {
            ""optionKey"": "ISOLATIONLEVEL"",
            ""optionValue"": ""1.0"",
            ""valueDataType"": ""1""
        },
        {
            ""optionKey"": ""USESCHEMA"",
            ""optionValue"": ""true"",
            ""valueDataType"": ""6""
        },
        {
            ""optionKey"": ""HOSTNAME"",
            ""optionValue"": ""192.168.1.100"",
            ""valueDataType"": ""2""
        },
        {
            ""optionKey"": ""PORT"",
            ""optionValue"": ""5432"",
            ""valueDataType"": ""1""
        },
        {
            ""optionKey"": ""DATABASE"",
            ""optionValue"": ""testdata"",
            ""valueDataType"": ""2""
        },
        {
            ""optionKey"": ""YF_DRIVER_SELECTION"",
            ""optionValue"": ""org.postgresql.Driver"",
            ""valueDataType"": ""2""
        }
    ]
}";

            string token = await GenerateToken(host, restUsername, restPassword);

            Console.WriteLine("Payload: " + createDataSourcePayload);

            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("YELLOWFIN", $"ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={new Random().NextInt64()}, token={token}");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.yellowfin.api-v1+json"));
                var content = new StringContent(createDataSourcePayload, System.Text.Encoding.UTF8, "application/json");

                HttpResponseMessage response = await httpClient.PostAsync($"{host}/api/data-sources", content);
                if (response.IsSuccessStatusCode)
                {
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine("Failed to create data source. Status code: " + response.StatusCode);
                }
            }
        }

        static async Task<string> GenerateToken(string host, string restUsername, string restPassword)
        {
            using (var client = new HttpClient())
            {
                // Generate nonce
                long nonce = new Random().NextInt64();

                // Create HTTP request
                var request = new HttpRequestMessage(HttpMethod.Post, $"{host}/api/refresh-tokens");
                request.Headers.Add("Authorization", $"YELLOWFIN ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}");
                request.Headers.Add("Accept", "application/vnd.yellowfin.api-v1+json");
                request.Content = new StringContent(
                    JsonConvert.SerializeObject(new { userName = restUsername, password = restPassword }),
                    System.Text.Encoding.UTF8,
                    "application/json"
                );

                // Send request and get response
                HttpResponseMessage response = await client.SendAsync(request);
                string responseContent = await response.Content.ReadAsStringAsync();

                // Parse JSON response
                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseContent);
                string accessToken = jsonObject["_embedded"]["accessToken"]["securityToken"].ToString();

                if (!string.IsNullOrEmpty(accessToken))
                {
                    Console.WriteLine("Access Token: " + accessToken);
                }
                else
                {
                    Console.WriteLine("Token not retrieved");
                    Environment.Exit(-1);
                }

                return accessToken;
            }
        }
    }
}
Code Block
titleGo
collapsetrue
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math/rand"
    "net/http"
    "time"
)

func main() {
	host := "http://localhost:8080/Yellowfin"
    restUsername := "admin@yellowfin.com.au"
    restPassword := "test"

    createDataSourcePayload := `{
        "sourceName": "PostgreSQL Database Created Via Import",
        "sourceDescription": "",
        "sourceType": "POSTGRESQL",
        "connectionType": "JDBC",
        "connectionTypeCode": "GENERICUSER",
        "connectionDriver": "org.postgresql.Driver",
        "connectionString": "jdbc:postgresql://192.168.1.100:5432/testdata",
        "connectionTimeout": 180,
        "userName": "postgres",
        "minimumConnections": 1,
        "maximumConnections": 5,
        "refreshTime": 180,
        "timezone": "AUSTRALIA/SYDNEY",
        "accessLevelCode": "UNSECURE",
        "maxRows": 10000,
        "maxAnalysisRows": 0,
        "inheritChildSourceFilters": false,
        "sourceLogIndicator": false,
        "sourceOptions": [
			{
                "optionKey": "ISOLATIONLEVEL",
                "optionValue": "1.0",
                "valueDataType": "1"
            },
			{
                "optionKey": "USESCHEMA",
                "optionValue": "true",
                "valueDataType": "6"
            },
			{
                "optionKey": "HOSTNAME",
                "optionValue": "192.168.1.100",
                "valueDataType": "2"
            },
			{
                "optionKey": "PORT",
                "optionValue": "5432",
                "valueDataType": "1"
            },
			{
                "optionKey": "DATABASE",
                "optionValue": "testdata",
                "valueDataType": "2"
            },
			{
                "optionKey": "YF_DRIVER_SELECTION",
                "optionValue": "org.postgresql.Driver",
                "valueDataType": "2"
            }
		]
	}`

	token, err := generateToken(host, restUsername, restPassword)
	if err != nil {
		fmt.Println("Error generating token:", err)
		return
	}

	fmt.Println("Payload:", createDataSourcePayload)

	client := &http.Client{}
	req, err := http.NewRequest("POST", host+"/api/data-sources", bytes.NewBuffer([]byte(createDataSourcePayload)))
	if err != nil {
		fmt.Println("Error creating request:", err)
		return
	}

	nonce := rand.Int63()

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d, token=%s", time.Now().UnixMilli(), nonce, token))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}

	fmt.Println(string(body))
}

func generateToken(host, restUsername, restPassword string) (string, error) {
	nonce := rand.Int63()

	requestBody, err := json.Marshal(map[string]string{
        "userName": restUsername,
        "password": restPassword,
	})
	if err != nil {
		fmt.Println("Error marshaling request body:", err)
		return "", err
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", host+"/api/refresh-tokens", bytes.NewBuffer(requestBody))
	if err != nil {
		fmt.Println("Error creating request:", err)
		return "", err
	}

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d", time.Now().UnixMilli(), nonce))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return "", err
	}

	var jsonResponse map[string]interface{}
	err = json.Unmarshal(body, &jsonResponse)
	if err != nil {
		fmt.Println("Error parsing JSON response:", err)
		return "", err
	}

	accessToken, ok := jsonResponse["_embedded"].(map[string]interface{})["accessToken"].(map[string]interface{})["securityToken"].(string)
	if !ok {
		fmt.Println("Token not retrieved")
		return "", fmt.Errorf("Token not retrieved successfully")
	}

	return accessToken, nil
}
Code Block
languagejs
titleJavaScript
collapsetrue
const fetch = require("node-fetch");

async function main() {
    const host = "http://localhost:8080/Yellowfin";
    const restUsername = "admin@yellowfin.com.au";
    const restPassword = "test";

    const createDataSourcePayload = `{
        "sourceName": "PostgreSQL Database Created Via Import",
        "sourceDescription": "",
        "sourceType": "POSTGRESQL",
        "connectionType": "JDBC",
        "connectionTypeCode": "GENERICUSER",
        "connectionDriver": "org.postgresql.Driver",
        "connectionString": "jdbc:postgresql://192.168.1.100:5432/testdata",
        "connectionTimeout": 180,
        "userName": "postgres",
        "minimumConnections": 1,
        "maximumConnections": 5,
        "refreshTime": 180,
        "timezone": "AUSTRALIA/SYDNEY",
        "accessLevelCode": "UNSECURE",
        "maxRows": 10000,
        "maxAnalysisRows": 0,
        "inheritChildSourceFilters": false,
        "sourceLogIndicator": false,
        "sourceOptions": [
            {
                "optionKey": "ISOLATIONLEVEL",
                "optionValue": "1.0",
                "valueDataType": "1"
            },
            {
                "optionKey": "USESCHEMA",
                "optionValue": "true",
                "valueDataType": "6"
            },
            {
                "optionKey": "HOSTNAME",
                "optionValue": "192.168.1.100",
                "valueDataType": "2"
            },
            {
                "optionKey": "PORT",
                "optionValue": "5432",
                "valueDataType": "1"
            },
            {
                "optionKey": "DATABASE",
                "optionValue": "testdata",
                "valueDataType": "2"
            },
            {
                "optionKey": "YF_DRIVER_SELECTION",
                "optionValue": "org.postgresql.Driver",
                "valueDataType": "2"
            }
        ]
    }`;

    const token = await generateToken(host, restUsername, restPassword);

    if (!token) {
        console.error("Failed to retrieve access token");
        return;
    }

    console.log("Payload:", createDataSourcePayload);

    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);

    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };

    try {
        const response = await fetch(`${host}/api/data-sources`, {
            method: 'POST',
            headers: headers,
            body: createDataSourcePayload
        });

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        const responseBody = await response.text();
        console.log(responseBody);
    } catch (error) {
        console.error("Error:", error.message);
    }
}

async function generateToken(host, restUsername, restPassword) {
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);

    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };

    const body = JSON.stringify({
        userName: restUsername,
        password: restPassword
    });

    try {
        const response = await fetch(`${host}/api/refresh-tokens`, {
            method: 'POST',
            headers: headers,
            body: body
        });

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        const jsonResponse = await response.json();
        const accessToken = jsonResponse._embedded.accessToken.securityToken;

        if (accessToken) {
            console.log(`Access Token: ${accessToken}`);
        } else {
            console.log("Token not retrieved");
        }

        return accessToken;
    } catch (error) {
        console.error("Error:", error.message);
    }

    return null;
}

main();
Code Block
languagephp
titlePHP
collapsetrue
<?php
function main() {
    $host = "http://localhost:8080/Yellowfin";
    $restUsername = "admin@yellowfin.com.au";
    $restPassword = "test";

    $createDataSourcePayload = '{
        "sourceName": "PostgreSQL Database Created Via Import",
        "sourceDescription": "",
        "sourceType": "POSTGRESQL",
        "connectionType": "JDBC",
        "connectionTypeCode": "GENERICUSER",
        "connectionDriver": "org.postgresql.Driver",
        "connectionString": "jdbc:postgresql://192.168.1.100:5432/testdata",
        "connectionTimeout": 180,
        "userName": "postgres",
        "minimumConnections": 1,
        "maximumConnections": 5,
        "refreshTime": 180,
        "timezone": "AUSTRALIA/SYDNEY",
        "accessLevelCode": "UNSECURE",
        "maxRows": 10000,
        "maxAnalysisRows": 0,
        "inheritChildSourceFilters": false,
        "sourceLogIndicator": false,
        "sourceOptions": [
            {
                "optionKey": "ISOLATIONLEVEL",
                "optionValue": "1.0",
                "valueDataType": "1"
            },
            {
                "optionKey": "USESCHEMA",
                "optionValue": "true",
                "valueDataType": "6"
            },
            {
                "optionKey": "HOSTNAME",
                "optionValue": "192.168.1.100",
                "valueDataType": "2"
            },
            {
                "optionKey": "PORT",
                "optionValue": "5432",
                "valueDataType": "1"
            },
            {
                "optionKey": "DATABASE",
                "optionValue": "testdata",
                "valueDataType": "2"
            },
            {
                "optionKey": "YF_DRIVER_SELECTION",
                "optionValue": "org.postgresql.Driver",
                "valueDataType": "2"
            }
        ]
    }';

    try {
        $token = generateToken($host, $restUsername, $restPassword);
    } catch (Exception $e) {
        echo "Error generating token: " . $e->getMessage();
        return;
    }

    echo "Payload: " . $createDataSourcePayload . "\n";

    $nonce = mt_rand();
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );

    try {
        $response = httpRequest('POST', "$host/api/data-sources", $headers, $createDataSourcePayload);
        echo $response;
    } catch (Exception $e) {
        echo "Error sending request: " . $e->getMessage();
    }
}

function generateToken($host, $restUsername, $restPassword) {
    // Generate nonce
    $nonce = mt_rand();

    // Create request body
    $requestBody = json_encode(array(
        "userName" => $restUsername,
        "password" => $restPassword
    ));

    // Create request headers
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );

    $response = httpRequest('POST', "$host/api/refresh-tokens", $headers, $requestBody);

    // Parse JSON response
    $jsonResponse = json_decode($response, true);

    // Get access token from response
    if (isset($jsonResponse["_embedded"]["accessToken"]["securityToken"])) {
        $accessToken = $jsonResponse["_embedded"]["accessToken"]["securityToken"];
        echo "Access Token: " . $accessToken;

        return $accessToken;
    } else {
        throw new Exception("Token not retrieved successfully");
    }
}

function httpRequest($method, $url, $headers, $data = null) {
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        throw new Exception('Error: ' . curl_error($ch));
    }

    curl_close($ch);

    return $response;
}

main();
?>
Code Block
languagepy
titlePython
collapsetrue
import json
import random
import time
import requests

def main():
    host = "http://localhost:8080/Yellowfin"
    rest_username = "admin@yellowfin.com.au"
    rest_password = "test"

    create_data_source_payload = '''
    {
        "sourceName": "PostgreSQL Database Created Via Import",
        "sourceDescription": "",
        "sourceType": "POSTGRESQL",
        "connectionType": "JDBC",
        "connectionTypeCode": "GENERICUSER",
        "connectionDriver": "org.postgresql.Driver",
        "connectionString": "jdbc:postgresql://192.168.1.100:5432/testdata",
        "connectionTimeout": 180,
        "userName": "postgres",
        "minimumConnections": 1,
        "maximumConnections": 5,
        "refreshTime": 180,
        "timezone": "AUSTRALIA/SYDNEY",
        "accessLevelCode": "UNSECURE",
        "maxRows": 10000,
        "maxAnalysisRows": 0,
        "inheritChildSourceFilters": false,
        "sourceLogIndicator": false,
        "sourceOptions": [
            {
                "optionKey": "ISOLATIONLEVEL",
                "optionValue": "1.0",
                "valueDataType": "1"
            },
            {
                "optionKey": "USESCHEMA",
                "optionValue": "true",
                "valueDataType": "6"
            },
            {
                "optionKey": "HOSTNAME",
                "optionValue": "192.168.1.100",
                "valueDataType": "2"
            },
            {
                "optionKey": "PORT",
                "optionValue": "5432",
                "valueDataType": "1"
            },
            {
                "optionKey": "DATABASE",
                "optionValue": "testdata",
                "valueDataType": "2"
            },
            {
                "optionKey": "YF_DRIVER_SELECTION",
                "optionValue": "org.postgresql.Driver",
                "valueDataType": "2"
            }
        ]
    }
    '''

    try:
        token = generate_token(host, rest_username, rest_password)
    except Exception as e:
        print(f"Error generating token: {e}")
        return

    print("Payload:", create_data_source_payload)

    nonce = random.randint(0, 2**63 - 1)

    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={nonce}, token={token}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(f"{host}/api/data-sources", headers=headers, data=create_data_source_payload)
        response.raise_for_status()
        print(response.text)
    except requests.RequestException as e:
        print(f"Error sending request: {e}")

def generate_token(host, rest_username, rest_password):
    nonce = random.randint(0, 2**63 - 1)

    # Create request body
    request_body = json.dumps({
        "userName": rest_username,
        "password": rest_password
    })

    # Create request headers
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={nonce}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(f"{host}/api/refresh-tokens", headers=headers, data=request_body)
        response.raise_for_status()
        json_response = response.json()
        access_token = json_response["_embedded"]["accessToken"]["securityToken"]
        print("Access Token:", access_token)
        return access_token
    except requests.RequestException as e:
        raise Exception("Token not retrieved successfully") from e

if __name__ == "__main__":
    main()

...

Code Block
languagejava
titleJava
collapsetrue
package rest.code.examples;
import java.io.IOException;
import java.util.Random;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * List DataSources using the Yellowfin REST API
 */
public class ListDataSources {
    public static void main(String[] args) throws Exception {

        System.out.print("List Datasources");


        String host = "http://localhost:8080/Yellowfin";
        String restUsername = "admin@yellowfin.com.au";
        String restPassword = "test";

        String token = generateToken(host, restUsername, restPassword);

        Content c = Request.get(host + "/api/data-sources")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + token)
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .execute().returnContent();

        System.out.print(c.asString());

    }


    /*
     *  This function generates an access token for a user that will grant them access to
     *  call REST API endpoints.
     */

    public static String generateToken(String host, String username, String password) throws IOException {

        Content c = Request.post(host + "/api/refresh-tokens")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong())
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .bodyString("{ \"userName\": \""+ username + "\",\"password\": \""+ password + "\"}", null)
                .execute().returnContent();

        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject("_embedded").getAsJsonObject("accessToken").get("securityToken");

        if (accessToken!=null) {
            System.out.println("Access Token: " + accessToken);
        } else {
            System.out.println("Token not retrieved successfully");
            System.exit(-1);
        }
        return accessToken.getAsString();

    }

}

...

Code Block
titleGo
collapsetrue
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math/rand"
    "net/http"
    "time"
)

func main() {
	host := "http://localhost:8080/Yellowfin"
    restUsername := "admin@yellowfin.com.au"
    restPassword := "test"

    token, err := generateToken(host, restUsername, restPassword)
	if err != nil {
		fmt.Println("Error generating token:", err)
		return
	}

	fmt.Println("List Datasources")

	client := &http.Client{}
	req, err := http.NewRequest("GET", host+"/api/data-sources", nil)
	if err != nil {
		fmt.Println("Error creating request:", err)
		return
	}

	nonce := rand.Int63()

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d, token=%s", time.Now().UnixMilli(), nonce, token))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}

	fmt.Println(string(body))
}

func generateToken(host, username, password string) (string, error) {
	// Generate nonce
	nonce := rand.Int63()

	// Create request body
	requestBody, err := json.Marshal(map[string]string{
        "userName": username,
        "password": password,
	})
	if err != nil {
		fmt.Println("Error marshaling request body:", err)
		return "", err
	}

	// Create HTTP client
	client := &http.Client{}

	// Create HTTP request
	request, err := http.NewRequest("POST", host+"/api/refresh-tokens", bytes.NewBuffer(requestBody))
	if err != nil {
		fmt.Println("Error creating request:", err)
		return "", err
	}

	// Add request headers
	request.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d", time.Now().UnixMilli(), nonce))
	request.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	request.Header.Set("Content-Type", "application/json")

	// Send HTTP request
	response, err := client.Do(request)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return "", err
	}
	defer response.Body.Close()

	// Read response body
	responseBody, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return "", err
	}

	// Parse JSON response
	var jsonResponse map[string]interface{}
	err = json.Unmarshal(responseBody, &jsonResponse)
	if err != nil {
		fmt.Println("Error parsing JSON response:", err)
		return "", err
	}

	// Get access token from response
	accessToken, ok := jsonResponse["_embedded"].(map[string]interface{})["accessToken"].(map[string]interface{})["securityToken"].(string)
	if !ok {
		fmt.Println("Token not retrieved")
		return "", fmt.Errorf("Token not retrieved successfully")
	}

	return accessToken, nil
}

...

Code Block
languagejava
titleJava
collapsetrue
package rest.code.examples;
import java.io.IOException;
import java.util.Random;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * Attach a Client Datasource to Primary Org Source for Source Substitution using the Yellowfin REST API
 */
public class AttachClientDatasourceToPrimarySource {
    public static void main(String[] args) throws Exception {

        System.out.print("Attach a Tenant Source to Primary Org Source for Source Substitution");

        String host = "http://localhost:8080/Yellowfin";
        String restUsername = "admin@yellowfin.com.au";
        String restPassword = "test";

        String primarySourceName = "PostgreSQL Connection at Primary Org";
        String clientSourceName = "PostgreSQL Connection for NEWCLIENT";
        String clientOrgReference = "NEWCLIENT";

        String clientToken = generateToken(host, restUsername, restPassword, clientOrgReference);
        Integer clientOrgSourceId = findDataSourceForSourceNameAtClient(host, clientToken, clientSourceName);

        System.out.println("Client Org Source Id: " + clientOrgSourceId);

        String primaryToken = generateToken(host, restUsername, restPassword, null);
        Integer primaryOrgSourceId = findDataSourceForSourceNameAtClient(host, primaryToken, primarySourceName);

        System.out.println("Primary Org Source Id: " + clientOrgSourceId);

        Content c = Request.get(host + "/api/data-sources/" + primaryOrgSourceId + "/client-data-sources/?clientSourceId=" + clientOrgSourceId)
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + primaryToken)
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .execute().returnContent();

        System.out.print(c.asString());

    }

    /*
     *  This function finds a datasource for a given datasource name
     *  call REST API endpoints.
     */

    private static Integer findDataSourceForSourceNameAtClient(String host, String token, String sourceName) throws IOException {

        Content c = Request.get(host + "/api/data-sources")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + token)
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .execute().returnContent();

        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement sourceList = jsonObject.get("items");
        JsonArray sources = sourceList.getAsJsonArray();

        for (int i=0; i < sources.size(); i++ ) {
            JsonObject source = sources.getAsJsonArray().get(i).getAsJsonObject();
            if (sourceName.equals(source.get("sourceName").getAsString())) return source.get("sourceId").getAsInt();
        }

        System.out.println("Data Source could not be found for name:" + sourceName);
        System.exit(-1);
        return null;

    }


    /*
     *  This function generates an access token for a user that will grant them access to
     *  call REST API endpoints.
     */

    public static String generateToken(String host, String username, String password, String tenantClientOrgRefId) throws IOException {

        String tokenBody = "{ \"userName\": \""+ username + "\",\"password\": \""+ password + "\"";
        if (tenantClientOrgRefId!=null) {
            tokenBody = tokenBody + ",\"clientOrgRef\": \""+ tenantClientOrgRefId + "\"";
        }
        tokenBody = tokenBody + "}";

        Content c = Request.post(host + "/api/refresh-tokens")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong())
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", "application/json")
                .bodyString(tokenBody, null)
                .execute().returnContent();

        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject("_embedded").getAsJsonObject("accessToken").get("securityToken");

        if (accessToken!=null) {
            System.out.println("Access Token: " + accessToken);
        } else {
            System.out.println("Token not retrieved successfully");
            System.exit(-1);
        }
        return accessToken.getAsString();

    }

}

...

Code Block
titleGo
collapsetrue
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math/rand"
    "net/http"
    "time"
)

func main() {
	fmt.Println("Attach a Tenant Source to Primary Org Source for Source Substitution")

	host := "http://localhost:8080/Yellowfin"
    restUsername := "admin@yellowfin.com.au"
    restPassword := "test"

    primarySourceName := "PostgreSQL Connection at Primary Org"
    clientSourceName := "PostgreSQL Connection for NEWCLIENT"
    clientOrgReference := "NEWCLIENT"

    clientToken, err := generateToken(host, restUsername, restPassword, clientOrgReference)
	if err != nil {
		fmt.Println("Error generating client token:", err)
		return
	}

	clientOrgSourceId, err := findDataSourceForSourceNameAtClient(host, clientToken, clientSourceName)
	if err != nil {
		fmt.Println("Error finding client data source:", err)
		return
	}
	fmt.Println("Client Org Source Id:", clientOrgSourceId)

	primaryToken, err := generateToken(host, restUsername, restPassword, "")
	if err != nil {
		fmt.Println("Error generating primary token:", err)
		return
	}

	primaryOrgSourceId, err := findDataSourceForSourceNameAtClient(host, primaryToken, primarySourceName)
	if err != nil {
		fmt.Println("Error finding primary data source:", err)
		return
	}
	fmt.Println("Primary Org Source Id:", primaryOrgSourceId)

	client := &http.Client{}
	nonce := rand.Int63()

	req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/data-sources/%d/client-data-sources/?clientSourceId=%d", host, primaryOrgSourceId, clientOrgSourceId), nil)
	if err != nil {
		fmt.Println("Error creating request:", err)
		return
	}

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d, token=%s", time.Now().UnixMilli(), nonce, primaryToken))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}

	fmt.Println(string(body))
}

func findDataSourceForSourceNameAtClient(host, token, sourceName string) (int, error) {
	client := &http.Client{}
	nonce := rand.Int63()

	req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/data-sources", host), nil)
	if err != nil {
		return 0, fmt.Errorf("Error creating request: %v", err)
	}

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d, token=%s", time.Now().UnixMilli(), nonce, token))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return 0, fmt.Errorf("Error sending request: %v", err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, fmt.Errorf("Error reading response body: %v", err)
	}

	var jsonResponse map[string]interface{}
	err = json.Unmarshal(body, &jsonResponse)
	if err != nil {
		return 0, fmt.Errorf("Error parsing JSON response: %v", err)
	}

	items := jsonResponse["items"].([]interface{})
	for _, item := range items {
		source := item.(map[string]interface{})
		if sourceName == source["sourceName"].(string) {
			sourceId := int(source["sourceId"].(float64))
			return sourceId, nil
		}
	}

	return 0, fmt.Errorf("Data Source could not be found for name: %s", sourceName)
}

func generateToken(host, username, password, tenantClientOrgRefId string) (string, error) {
	nonce := rand.Int63()

	tokenBody := map[string]string{
        "userName": username,
        "password": password,
	}
	if tenantClientOrgRefId != "" {
		tokenBody["clientOrgRef"] = tenantClientOrgRefId
	}

	requestBody, err := json.Marshal(tokenBody)
	if err != nil {
		return "", fmt.Errorf("Error marshaling request body: %v", err)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/api/refresh-tokens", host), bytes.NewBuffer(requestBody))
	if err != nil {
		return "", fmt.Errorf("Error creating request: %v", err)
	}

	req.Header.Set("Authorization", fmt.Sprintf("YELLOWFIN ts=%d, nonce=%d", time.Now().UnixMilli(), nonce))
	req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("Error sending request: %v", err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("Error reading response body: %v", err)
	}

	var jsonResponse map[string]interface{}
	err = json.Unmarshal(body, &jsonResponse)
	if err != nil {
		return "", fmt.Errorf("Error parsing JSON response: %v", err)
	}

	embedded := jsonResponse["_embedded"].(map[string]interface{})
	accessToken := embedded["accessToken"].(map[string]interface{})["securityToken"].(string)

	if accessToken == "" {
		return "", fmt.Errorf("Token not retrieved successfully")
	}

	fmt.Println("Access Token:", accessToken)
	return accessToken, nil
}

...

Code Block
languagephp
titlePHP
collapsetrue
<?php

function main() {
    $host = "http://localhost:8080/Yellowfin";
    $restUsername = "admin@yellowfin.com.au";
    $restPassword = "test";

    echo "Attach a Tenant Source to Primary Org Source for Source Substitution\n";

    $primarySourceName = "PostgreSQL Connection at Primary Org";
    $clientSourceName = "PostgreSQL Connection for NEWCLIENT";
    $clientOrgReference = "NEWCLIENT";

    try {
        $clientToken = generateToken($host, $restUsername, $restPassword, $clientOrgReference);
        $clientOrgSourceId = findDataSourceForSourceNameAtClient($host, $clientToken, $clientSourceName);

        echo "Client Org Source Id: $clientOrgSourceId\n";

        $primaryToken = generateToken($host, $restUsername, $restPassword, null);
        $primaryOrgSourceId = findDataSourceForSourceNameAtClient($host, $primaryToken, $primarySourceName);

        echo "Primary Org Source Id: $primaryOrgSourceId\n";

        $headers = [
            'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . mt_rand() . ', token=' . $primaryToken,
            'Accept: application/vnd.yellowfin.api-v1+json',
            'Content-Type: application/json'
        ];

        $url = "$host/api/data-sources/$primaryOrgSourceId/client-data-sources/?clientSourceId=$clientOrgSourceId";
        $response = httpRequest('GET', $url, $headers);

        echo $response;
    } catch (Exception $e) {
        echo "Error: " . $e->getMessage();
    }
}

function generateToken($host, $restUsername, $restPassword, $tenantClientOrgRefId = null) {
    $nonce = mt_rand();

    $tokenBody = "{ \"userName\": \"$restUsername\", \"password\": \"$restPassword\"";
    if ($tenantClientOrgRefId !== null) {
        $tokenBody .= ", \"clientOrgRef\": \"$tenantClientOrgRefId\"";
    }
    $tokenBody .= "}";

    $headers = [
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    ];

    $response = httpRequest('POST', "$host/api/refresh-tokens", $headers, $tokenBody);

    $jsonResponse = json_decode($response, true);

    if (isset($jsonResponse["_embedded"]["accessToken"]["securityToken"])) {
        return $jsonResponse["_embedded"]["accessToken"]["securityToken"];
    } else {
        throw new Exception("Token not retrieved successfully");
    }
}

function findDataSourceForSourceNameAtClient($host, $token, $sourceName) {
    $headers = [
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . mt_rand() . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    ];

    $response = httpRequest('GET', "$host/api/data-sources", $headers);

    $jsonObject = json_decode($response);

    if (isset($jsonObject->items)) {
        foreach ($jsonObject->items as $source) {
            if ($source->sourceName === $sourceName) {
                return $source->sourceId;
            }
        }
    }

    echo "Data Source could not be found for name: $sourceName\n";
    exit(-1);
}

function httpRequest($method, $url, $headers, $data = null) {
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        throw new Exception('Error: ' . curl_error($ch));
    }

    curl_close($ch);

    return $response;
}

main();
?>

...