30日間の無料評価版をお試しいただけます。

ISVのデプロイ戦略では、各クライアントに対してソフトウェアのオンプレミスインストールをデプロイする必要があります。この場合、Yellowfin ライセンスの置き換えが必要になったときに、それが困難になる場合があります。

リモート環境でライセンスを更新するには、2つの方法があります。1つは、REST サービスを介してライセンスをプッシュする方法で、もう1つは、Yellowfin インスタンス自体で設定可能なプルメカニズムを可能にすることです。

REST APIを使用したライセンスの更新

POST /api/rpc/licence-management/upload-licence エンドポイント Upload License を使用することで、動作中のYellowfin インスタンスでライセンスを更新することができます。

この特定のエンドポイントは、送信パラダイムに基づくフォームを使用します。「newLicence」という名前のフォーム本体が1つ必要で、その中にライセンスファイルのコンテンツが含まれていなければなりません。

以下のコード例では、POST /api/rpc/licence-management/upload-licence エンドポイントを使用して、ライセンスファイルをアップロードする方法を示しています。

Java
package rest.code.examples;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
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.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * Upload License File via the Yellowfin REST API
 */
public class UploadALicenseFile {
    public static void main(String[] args) throws Exception {
 
        System.out.println("Upload License File");
 
        String host = "http://localhost:8080/Yellowfin";
        String restUsername = "admin@yellowfin.com.au";
        String restPassword = "test";
 
        String fileToImport = "/Downloads/Yellowfin-License.lic";
        Path licenseFile = Paths.get(fileToImport);
        byte[] fileContents = Files.readAllBytes(licenseFile);
        String token = generateToken(host, restUsername, restPassword);
 
        HttpEntity newLicenseFileMulitpartEntity = MultipartEntityBuilder
                .create()
                .setMode(HttpMultipartMode.LEGACY)
                .setCharset(Charset.forName("UTF-8"))
                .addBinaryBody("newLicence", fileContents , ContentType.DEFAULT_BINARY, licenseFile.getFileName().toString())
                .build();
 
 
        System.out.println("Upload License Content");
        Content uploadLicenseContent = Request.post(host + "/api/rpc/licence-management/upload-licence")
                .addHeader("Authorization", "YELLOWFIN ts=" + System.currentTimeMillis() + " , nonce=" + new Random().nextLong() + ", token=" + token)
                .addHeader("Accept", "application/vnd.yellowfin.api-v1+json")
                .addHeader("Content-Type", newLicenseFileMulitpartEntity.getContentType())
                .addHeader("cache-control", "no-cache")
                .body(newLicenseFileMulitpartEntity)
                .execute()
                .returnContent();
 
        System.out.println("License Upload Complete");
        System.out.println(uploadLicenseContent.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();
 
    }
 
}
C#
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
 
namespace YellowfinAPIExamples
{
    public class UploadALicenseFile
    {
        public static async Task Main(string[] args)
        {
            Console.WriteLine("Upload License File");
 
            string host = "http://localhost:8080/Yellowfin";
            string restUsername = "admin@yellowfin.com.au";
            string restPassword = "test";
 
            string fileToImport = "/Downloads/Yellowfin-License.lic";
            byte[] fileContents = File.ReadAllBytes(fileToImport);
            string token = await GenerateToken(host, restUsername, restPassword);
 
            MultipartFormDataContent multipartContent = new MultipartFormDataContent();
            ByteArrayContent fileContent = new ByteArrayContent(fileContents);
            fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
            multipartContent.Add(fileContent, "newLicence", Path.GetFileName(fileToImport));
 
            Console.WriteLine("Upload License Content");
 
            using (var httpClient = new HttpClient())
            {
                long nonce = new Random().NextInt64();
 
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("YELLOWFIN", $"ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}, token={token}");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.yellowfin.api-v1+json"));
 
                HttpResponseMessage response = await httpClient.PostAsync(host + "/api/rpc/licence-management/upload-licence", multipartContent);
                if (response.IsSuccessStatusCode)
                {
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine("License Upload Complete");
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine($"Failed to upload license. Status code: {response.StatusCode}");
                }
            }
        }
 
        public static async Task<string> GenerateToken(string host, string username, string password)
        {
            using (var client = new HttpClient())
            {
                long nonce = new Random().NextInt64();
 
                var requestBody = new
                {
                    userName = username,
                    password = password
                };
                string jsonRequestBody = JsonConvert.SerializeObject(requestBody);
 
                var request = new HttpRequestMessage(HttpMethod.Post, host + "/api/refresh-tokens");
                request.Headers.Add("Authorization", $"YELLOWFIN ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}");
                request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.yellowfin.api-v1+json"));
                request.Content = new StringContent(jsonRequestBody, 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 successfully");
                    Environment.Exit(-1);
                }
 
                return accessToken;
            }
        }
    }
}
Go
package main
 
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "io/ioutil"
    "math/rand"
    "mime/multipart"
    "net/http"
    "os"
    "path/filepath"
    "time"
)
 
func main() {
    fmt.Println("Upload License File")
 
    host := "http://localhost:8080/Yellowfin"
    restUsername := "admin@yellowfin.com.au"
    restPassword := "test"
 
    fileToImport := "/Downloads/Yellowfin-License.lic"
    filePath := filepath.Clean(fileToImport)
 
    token, err := generateToken(host, restUsername, restPassword)
    if err != nil {
        fmt.Println("Error generating token:", err)
        return
    }
 
    file, err := os.Open(filePath)
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer file.Close()
 
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
 
    part, err := writer.CreateFormFile("newLicence", filepath.Base(filePath))
    if err != nil {
        fmt.Println("Error writing to buffer:", err)
        return
    }
 
    _, err = io.Copy(part, file)
    if err != nil {
        fmt.Println("Error copying file to buffer:", err)
        return
    }
 
    err = writer.Close()
    if err != nil {
        fmt.Println("Error closing writer:", err)
        return
    }
 
    nonce := rand.Int63()
 
    req, err := http.NewRequest("POST", host+"/api/rpc/licence-management/upload-licence", body)
    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, token))
    req.Header.Set("Accept", "application/vnd.yellowfin.api-v1+json")
    req.Header.Set("Content-Type", writer.FormDataContentType())
 
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error sending request:", err)
        return
    }
    defer resp.Body.Close()
 
    fmt.Println("License Upload Complete")
    responseBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Error reading response body:", err)
        return
    }
    fmt.Println(string(responseBody))
}
 
func generateToken(host, restUsername, restPassword string) (string, error) {
    nonce := rand.Int63()
 
    reqBody := fmt.Sprintf(`{"userName": "%s", "password": "%s"}`, restUsername, restPassword)
 
    req, err := http.NewRequest("POST", host+"/api/refresh-tokens", bytes.NewBufferString(reqBody))
    if err != nil {
        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")
 
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
 
    respBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
 
    var jsonResponse map[string]interface{}
    if err := json.Unmarshal(respBody, &jsonResponse); err != nil {
        return "", err
    }
 
    accessToken, ok := jsonResponse["_embedded"].(map[string]interface{})["accessToken"].(map[string]interface{})["securityToken"].(string)
    if !ok {
        return "", fmt.Errorf("Token not retrieved successfully")
    }
 
    return accessToken, nil
}
JavaScript
const fs = require('fs');
const FormData = require('form-data');
const fetch = require('node-fetch');
 
async function main() {
    const host = "http://localhost:8080/Yellowfin";
    const restUsername = "admin@yellowfin.com.au";
    const restPassword = "test";
 
    const fileToImport = "/Downloads/Yellowfin-License.lic";
    const fileContents = fs.readFileSync(fileToImport);
    const fileName = fileToImport.split('/').pop(); // Extracting filename from path
 
    const token = await generateToken(host, restUsername, restPassword);
 
    if (!token) {
        console.error("Failed to retrieve access token");
        return;
    }
 
    console.log("Upload License File");
 
    const formData = new FormData();
    formData.append('newLicence', fileContents, { filename: fileName });
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${generateNonce()}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        ...formData.getHeaders()
    };
 
    try {
        const response = await fetch(`${host}/api/rpc/licence-management/upload-licence`, {
            method: 'POST',
            headers: headers,
            body: formData
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const responseBody = await response.text();
        console.log("License Upload Complete");
        console.log(responseBody);
    } catch (error) {
        console.error("Error:", error.message);
    }
}
 
async function generateToken(host, restUsername, restPassword) {
    const nonce = generateNonce();
 
    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;
}
 
function generateNonce() {
    return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
}
 
main();
PHP
<?php
function main() {
    $host = "http://localhost:8080/Yellowfin";
    $restUsername = "admin@yellowfin.com.au";
    $restPassword = "test";
 
    $fileToImport = "/Downloads/Yellowfin-License.lic";
 
    try {
        $token = generateToken($host, $restUsername, $restPassword);
    } catch (Exception $e) {
        echo "Error generating token: " . $e->getMessage();
        return;
    }
 
    // Read file contents
    try {
        $fileContents = file_get_contents($fileToImport);
    } catch (Exception $e) {
        echo "Error reading file: " . $e->getMessage();
        return;
    }
 
    $fileName = basename($fileToImport);
 
    // Build multipart form data
    $importOptions = json_encode(array(
        "option1" => "value1",
        "option2" => "value2"
    ));
 
    $multipartBody = buildMultipartEntity($fileContents, $fileName, $importOptions);
 
    echo "Upload License Content\n";
    try {
        $response = sendMultipartRequest($host, $token, $multipartBody, "/api/rpc/licence-management/upload-licence");
        echo "License Upload Complete\n";
        echo $response . "\n";
    } catch (Exception $e) {
        echo "Error uploading license: " . $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'
    );
 
    try {
        $response = httpRequest('POST', "$host/api/refresh-tokens", $headers, $requestBody);
        $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");
        }
    } catch (Exception $e) {
        throw new Exception("Error generating token: " . $e->getMessage());
    }
}
 
function buildMultipartEntity($fileContents, $fileName, $importOptions) {
    $boundary = uniqid();
 
    $multipartBody = "--$boundary\r\n";
    $multipartBody .= 'Content-Disposition: form-data; name="newLicence"; filename="' . $fileName . "\"\r\n";
    $multipartBody .= "Content-Type: application/octet-stream\r\n\r\n";
    $multipartBody .= $fileContents . "\r\n";
 
    $multipartBody .= "--$boundary\r\n";
    $multipartBody .= 'Content-Disposition: form-data; name="importOptions"' . "\r\n";
    $multipartBody .= "Content-Type: application/json\r\n\r\n";
    $multipartBody .= $importOptions . "\r\n";
 
    $multipartBody .= "--$boundary--";
 
    return $multipartBody;
}
 
function sendMultipartRequest($host, $token, $multipartBody, $endpoint) {
    $boundary = substr($multipartBody, 2, strpos($multipartBody, "\r\n") - 2);
 
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . mt_rand() . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: multipart/form-data; boundary=' . $boundary,
        'cache-control: no-cache'
    );
 
    try {
        $response = httpRequest('POST', "$host$endpoint", $headers, $multipartBody);
        return $response;
    } catch (Exception $e) {
        throw new Exception("Error sending multipart request: " . $e->getMessage());
    }
}
 
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();
?>
Python
import json
import random
import time
import os
import requests
 
def main():
    host = "http://localhost:8080/Yellowfin"
    rest_username = "admin@yellowfin.com.au"
    rest_password = "test"
 
    file_to_import = "/Downloads/Yellowfin-License.lic"
    token = generate_token(host, rest_username, rest_password)
 
    # Ensure the file exists
    if not os.path.exists(file_to_import):
        print(f"Error: File '{file_to_import}' not found.")
        return
 
    # Read file contents
    with open(file_to_import, 'rb') as file:
        file_contents = file.read()
 
    # Prepare headers
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}, token={token}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'cache-control': 'no-cache'
    }
 
    # Prepare multipart form data manually
    files = {
        'newLicence': (file_to_import, file_contents, 'application/octet-stream')
    }
 
    try:
        response = requests.post(f"{host}/api/rpc/licence-management/upload-licence", headers=headers, files=files)
        response.raise_for_status()
        print("License Upload Complete")
        print(response.text)
    except requests.RequestException as e:
        print(f"Error uploading license: {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()

ライセンス自動プロビジョニング

ライセンス自動プロビジョニングは、Yellowfin インスタンスがリモードサーバで新しいライセンスファイルを探すための組み込みメカニズムです。これは、web.xml ファイルで、LicenceAutoProvision サーブレットを有効にすることで設定できます。

これは、Yellowfinが定期的にサーバに接続して新しいライセンスを探すように設定できます。サーバからダウンロードされたライセンスファイルが、現在インストールされているライセンスと異なる場合、そのファイルが取り込まれ、ライセンスが置き換えられます。これにより、分散インストールを行うISVは、定義されたサーバの場所でライセンスを更新することで、リモートでライセンスの更新を管理することができます。

サーバは、HTTP、HTTPS、またはSFTPで動作します。HTTPとHTTPSは、ベーシック認証をサポートし、SFTPは、接続にユーザー認証が必要です。

<servlet>
        <servlet-name>LicenceAutoProvision</servlet-name>
        <servlet-class>com.hof.servlet.LicenceAutoProvision</servlet-class>
        <init-param>
            <param-name>Enabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>TaskPeriodInterval</param-name>
            <param-value>360</param-value>
        </init-param>
        <init-param>
            <param-name>Protocol</param-name>
            <param-value>http</param-value>  
<!--            <param-value>https</param-value>--> 
<!--            <param-value>sftp</param-value>-->
        </init-param>
        <init-param>
            <param-name>Hostname</param-name>
            <param-value>localhost</param-value>
        </init-param>
        <init-param>
            <param-name>Port</param-name>
            <param-value>8100</param-value>
        </init-param>
        <init-param>
            <param-name>PathToLicenceFile</param-name>
            <param-value>/static/licence.lic</param-value>
        </init-param>
        <init-param>
            <param-name>Username</param-name>
            <param-value>demo</param-value>
        </init-param>
        <init-param>
            <param-name>Password</param-name>
            <param-value>demo</param-value>
        </init-param>
        <load-on-startup><!-- can use 9 or greater, as long as its one of the last servlet initialized --></load-on-startup>
    </servlet>