Skip to content
Snippets Groups Projects
jsonld.js 8.8 KiB
Newer Older
import {send as notify} from './notification';
import * as utils from "./utils";
import {i18n} from "./i18n";

let instances = {};
let successFunctions = {};
let failureFunctions = {};
let initStarted = {};

// "module.exports = class JSONLD" doesn't work with rollup because of above "import"
export default class JSONLD {
    constructor(baseApiUrl, entities) {
        this.entities = entities;
        this.baseApiUrl = baseApiUrl;

        let idToEntityNameMatchList = {};
        for (const entityName in entities) {
            const id = entities[entityName]["@id"];
            idToEntityNameMatchList[id] = entityName;
        }

        this.idToEntityNameMatchList = idToEntityNameMatchList;
    }

    static initialize(apiUrl, successFnc, failureFnc) {
        // if init api call was already successfully finished execute the success function
        if (instances[apiUrl] !== undefined) {
            if (typeof successFnc == 'function') successFnc(instances[apiUrl]);

            return;
        }

        // init the arrays
        if (successFunctions[apiUrl] === undefined) successFunctions[apiUrl] = [];
        if (failureFunctions[apiUrl] === undefined) failureFunctions[apiUrl] = [];

        // add success and failure functions
        if (typeof successFnc == 'function') successFunctions[apiUrl].push(successFnc);
        if (typeof failureFnc == 'function') failureFunctions[apiUrl].push(failureFnc);

        // check if api call was already started
        if (initStarted[apiUrl] !== undefined) {
            return;
        }

        initStarted[apiUrl] = true;

        if (window.VPUAuthToken !== undefined) {
            JSONLD.doInitialization(apiUrl);
        } else {
            // window.VPUAuthToken will be set by vpu-auth-init event
            window.addEventListener("vpu-auth-init", () => JSONLD.doInitialization(apiUrl));
        }
    }

    static doInitialization(apiUrl) {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", apiUrl, true);
        xhr.setRequestHeader('Authorization', 'Bearer ' + window.VPUAuthToken);

        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    const json = JSON.parse(xhr.responseText);

                    let entryPoints = {};
                    for (let property in json) {
                        // for some reason the properties start with a lower case character
                        if (!property.startsWith("@")) entryPoints[property.toLowerCase()] = json[property];
                    }

                    // read the link header of the api response
                    //                const utils = require("./utils");
                    const links = utils.parseLinkHeader(this.getResponseHeader("link"));

                    // get the hydra apiDocumentation url
                    const apiDocUrl = links["http://www.w3.org/ns/hydra/core#apiDocumentation"];

                    if (apiDocUrl !== undefined) {
                        // load the hydra apiDocumentation
                        const docXhr = new XMLHttpRequest();
                        docXhr.open("GET", apiDocUrl, true);
                        docXhr.setRequestHeader("Content-Type", "application/json");
                        docXhr.onreadystatechange = function () {
                            if (docXhr.readyState === 4) {
                                if (docXhr.status === 200) {
                                    const json = JSON.parse(docXhr.responseText);
                                    const supportedClasses = json["hydra:supportedClass"];

                                    let entities = {};
                                    const baseUrl = utils.parseBaseUrl(apiUrl);

                                    // gather the entities
                                    supportedClasses.forEach(function (classData) {
                                        // add entry point url
                                        const entityName = classData["hydra:title"];
                                        let entryPoint = entryPoints[entityName.toLowerCase()];
                                        if (entryPoint !== undefined && !entryPoint.startsWith("http")) entryPoint = baseUrl + entryPoint;
                                        classData["@entryPoint"] = entryPoint;

                                        entities[entityName] = classData;
                                    });

                                    const instance = new JSONLD(baseUrl, entities);
                                    instances[apiUrl] = instance;

                                    // return the initialized JSONLD object
                                    for (const fnc of successFunctions[apiUrl]) if (typeof fnc == 'function') fnc(instance);
                                    successFunctions[apiUrl] = [];
                                } else {
                                    JSONLD.executeFailureFunctions(apiUrl, i18n.t('jsonld.api-documentation-server', {apiUrl: apiDocUrl}));
                                }
                            }
                        };

                        docXhr.send();
                    } else {
                        JSONLD.executeFailureFunctions(apiUrl, i18n.t('jsonld.error-hydra-documentation-url-not-set', {apiUrl: apiUrl}));
                    }
                    JSONLD.executeFailureFunctions(apiUrl, i18n.t('jsonld.error-api-server', {apiUrl: apiUrl}));
    /**
     * Execute failure functions and send general notification
     *
     * @param apiUrl
     * @param message
     */
    static executeFailureFunctions(apiUrl, message = "") {
        for (const fnc of failureFunctions[apiUrl]) if (typeof fnc == 'function') fnc();
        failureFunctions[apiUrl] = [];

        if (message !== "") {
            notify({
                "summary": i18n.t('error.summary'),
                "body": message,
                "type": "danger",
            });
        }
    }

    static getInstance(apiUrl) {
        return instances[apiUrl];
    }

    getEntityForIdentifier(identifier) {
        let entityName = this.getEntityNameForIdentifier(identifier);
        return this.getEntityForEntityName(entityName);
    }

    getEntityForEntityName(entityName) {
        return this.entities[entityName];
    }

    getApiUrlForIdentifier(identifier) {
        const entity = this.getEntityForIdentifier(identifier);

        if (entity === undefined || entity["@entryPoint"] === undefined) {
            throw new Error(`Entity with identifier "${identifier}" not found!`);
        }

        return entity["@entryPoint"];
    }

    getApiUrlForEntityName(entityName) {
        const entity = this.getEntityForEntityName(entityName);

        if (entity === undefined || entity["@entryPoint"] === undefined) {
            throw new Error(`Entity "${entityName}" not found!`);
        }

        return entity["@entryPoint"];
    }

    getEntityNameForIdentifier(identifier) {
        return this.idToEntityNameMatchList[identifier];
    }

    getApiIdentifierList() {
        let keys = [];
        for (const property in this.idToEntityNameMatchList) {
            keys.push(property);
        }

        return keys;
    }

    /**
     * Expands a member of a list to a object with schema.org properties
     *
     * @param member
     */
    expandMember(member) {
        const type = member["@type"];

        const entity = this.getEntityForIdentifier(type);
        let result = {"@id": member["@id"]};

        entity["hydra:supportedProperty"].forEach(function (property) {
            const id = property["hydra:property"]["@id"];
            const title = property["hydra:title"];

            result[id] = member[title];
        });

        return result;
    }

    /**
     * Compacts an expanded member of a list to a object with local properties
     *
     * @param member
     * @param localContext
     */
    static compactMember(member, localContext) {
        let result = {};

        for (const property in localContext) {
            const value = member[localContext[property]];

            if (value !== undefined) {
                result[property] = value;
            }
        }

        return result;
    }

    /**
     * Transforms hydra members to a local context
     *
     * @param data
     * @param localContext
     * @returns {Array}
     */
    transformMembers(data, localContext) {
        const members = data['hydra:member'];

        if (members === undefined || members.length === 0) {
            return [];
        }

        let results = [];
        let that = this;

        members.forEach(function (member) {
            results.push(JSONLD.compactMember(that.expandMember(member), localContext));
        });

        return results;
    }
};