All Downloads are FREE. Search and download functionalities are using the official Maven repository.

be.ugent.rml.functions.FunctionUtils Maven / Gradle / Ivy

Go to download

The RMLMapper executes RML rules to generate high quality Linked Data from multiple originally (semi-)structured data sources.

There is a newer version: 7.2.0
Show newest version
package be.ugent.rml.functions;

import be.ugent.rml.NAMESPACES;
import be.ugent.rml.Utils;
import be.ugent.rml.store.Quad;
import be.ugent.rml.store.QuadStore;
import be.ugent.rml.term.NamedNode;
import be.ugent.rml.term.Term;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.time.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FunctionUtils {

    private static final Logger logger = LoggerFactory.getLogger(FunctionUtils.class);

    public static Class functionRequire(File file, String className) throws IOException {
        String path = file.getPath();
        if (path.endsWith(".jar")) {
            return FunctionUtils.getClass(file, className, "application/java-archive");
        } else if (path.endsWith(".java")) {
            return FunctionUtils.getClass(file, className, "text/x-java-source");
        }

        throw new IOException("Not a valid path for a JAVA implementation: " + path);
    }

    public static List getFunctionParameterUris(QuadStore store, List parameterResources) {
        List parameterPredicates = new ArrayList<>();

        for (Term subject : parameterResources) {
            parameterPredicates.add(Utils.getObjectsFromQuads(getQuadsByFunctionPrefix(store, subject, "predicate", null)).get(0));
        }

        return parameterPredicates;
    }

    public static Class[] parseFunctionParameters(QuadStore store, List parameterResources) {
        Class[] args = new Class[parameterResources.size()];

        for (int i = 0; i < parameterResources.size(); i++) {
            Term subject = parameterResources.get(i);
            Term type = Utils.getObjectsFromQuads(getQuadsByFunctionPrefix(store, subject, "type", null)).get(0);

            try {
                args[i] = FunctionUtils.getParamType(type);
            } catch (Exception e) {
                args[i] = String.class;
            }
        }
        return args;
    }

    /**
     * Generates strings from a function object. Possible lists/sets/bags/... in the object are unrolled recursively
     * and a string value is generated from each "simple" (i.e., not a list/set/bag/...) child object.
     *
     * @param o      Function object, can be iterable.
     * @param result A string list to which string values of objects are added
     */
    public static void functionObjectToList(Object o, List result) {
        if (o != null) {
            // if o has child objects, recursively call this function on each child
            if (o instanceof Iterable) {
                ((Iterable) o).forEach(item -> {
                    functionObjectToList(item, result);
                });
            }
            // if o has no children, call toString() to serialize it into a string
            else {
                // numeric and boolean types are trivially serialized correctly
                // times/dates objects in the java.time package use the relevant ISO-8601 standard,
                // which is also used by xsd types and thus RDF types
                result.add(o.toString());
            }
        }
    }

    private static Class getParamType(Term type) {
        String typeStr = type.getValue();

        switch (typeStr) {
            // This is quite crude, based on https://www.w3.org/TR/xmlschema11-2/#built-in-datatypes
            case "http://www.w3.org/2001/XMLSchema#any":
                return Object.class;
            case "http://www.w3.org/2001/XMLSchema#string":
                return String.class;
            case "http://www.w3.org/2001/XMLSchema#unsignedLong":
            case "http://www.w3.org/2001/XMLSchema#long":
                return Long.class;
            case "http://www.w3.org/2001/XMLSchema#integer":
            case "http://www.w3.org/2001/XMLSchema#int":
            case "http://www.w3.org/2001/XMLSchema#short":
            case "http://www.w3.org/2001/XMLSchema#byte":
            case "http://www.w3.org/2001/XMLSchema#nonNegativeInteger":
            case "http://www.w3.org/2001/XMLSchema#positiveInteger":
            case "http://www.w3.org/2001/XMLSchema#unsignedInt":
            case "http://www.w3.org/2001/XMLSchema#unsignedShort":
            case "http://www.w3.org/2001/XMLSchema#unsignedByte":
            case "http://www.w3.org/2001/XMLSchema#nonPositiveInteger":
            case "http://www.w3.org/2001/XMLSchema#negativeInteger":
                return Integer.class;
            case "http://www.w3.org/2001/XMLSchema#boolean":
                return Boolean.class;
            case "http://www.w3.org/2001/XMLSchema#date":
                // "Local" just means "without a time zone"
                return LocalDate.class;
            case "http://www.w3.org/2001/XMLSchema#dateTime":
                // again "Local" means "without a time zone"
                // (An xsd:dateTime actually has an OPTIONAL time zone, so there is a small semantic difference
                // with java.time.LocalDateTime, this is a best effort.)
                return LocalDateTime.class;
            case "http://www.w3.org/2001/XMLSchema#dateTimeStamp":
                return ZonedDateTime.class;
            case "http://www.w3.org/2001/XMLSchema#dayTimeDuration":
            case "http://www.w3.org/2001/XMLSchema#yearMonthDuration":
                return Duration.class;
            case "http://www.w3.org/2001/XMLSchema#gDay":
                // TODO there is no java.time equivalent of xsd:day
                // (There is java.time.DayOfWeek, but xsd:day would corresponds to java.time.DayOfMonth .)
                throw new DateTimeException("There is no java.time equivalent of xsd:day. Crashing.");
            case "http://www.w3.org/2001/XMLSchema#gMonth":
                return Month.class;
            case "http://www.w3.org/2001/XMLSchema#gMonthDay":
                return MonthDay.class;
            case "http://www.w3.org/2001/XMLSchema#gYear":
                return Year.class;
            case "http://www.w3.org/2001/XMLSchema#gYearMonth":
                return YearMonth.class;
            case "http://www.w3.org/2001/XMLSchema#decimal":
            case "http://www.w3.org/2001/XMLSchema#double":
            case "http://www.w3.org/2001/XMLSchema#float":
                return Double.class;
            case "http://www.w3.org/1999/02/22-rdf-syntax-ns#List":
                return List.class;
            default:
                throw new Error("Couldn't derive type from " + type);
        }
    }

    private static Class getClass(File sourceFile, String className, String mime) throws IOException {
        logger.info("Found class on path " + sourceFile.getCanonicalPath());

        switch (mime) {
            case "text/x-java-source":
                return FunctionUtils.getClassFromJAVA(sourceFile, className);
            case "application/java-archive":
                return FunctionUtils.getClassFromJAR(sourceFile, className);
        }

        return null;
    }

    private static Class getClassFromJAVA(File sourceFile, String className) {
        Class cls = null;

        // TODO let's not recompile every time
        // Compile source file.
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int res = compiler.run(null, null, null, sourceFile.getPath());

        if (res != 0) {
            return null;
        }

        // Load and instantiate compiled class.
        URLClassLoader classLoader = null;
        try {
            classLoader = URLClassLoader.newInstance(new URL[]{(new File(sourceFile.getParent())).toURI().toURL()});
            cls = Class.forName(className, true, classLoader);
        } catch (MalformedURLException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        return cls;
    }

    private static Class getClassFromJAR(File sourceFile, String className) {
        Class cls = null;

        URLClassLoader child = null;
        try {
            child = URLClassLoader.newInstance(new URL[]{sourceFile.toURI().toURL()});
            cls = Class.forName(className, true, child);
        } catch (MalformedURLException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        return cls;
    }

    /**
     * Retrieve triples of a store based on a predicate, taking into account deprecated FnO prefixed predicates
     * @param store The triple store to retrieve the triples from
     * @param s the subject
     * @param functionTerm the unprefixed function term
     * @param o the object
     * @return the quads that are conform to the triple pattern fragment
     */
    static List getQuadsByFunctionPrefix(QuadStore store, Term s, String functionTerm, Term o) {
        List prefices = Arrays.asList(NAMESPACES.FNO_S, NAMESPACES.FNO, NAMESPACES.FNO_OLD);
        return getQuadsByPrefix(store, s, functionTerm, o, prefices);
    }

    /**
     * Retrieve triples of a store based on a predicate, taking into account multiple prefixes
     * @param store The triple store to retrieve the triples from
     * @param s the subject
     * @param pString the unprefixed predicate term
     * @param o the object
     * @param prefices the list of prefices on which to look for, in order of 'correctness' (all prefixes except for the first one are assumed deprecated)
     * @return the quads that are conform to the triple pattern fragment
     */
    private static List getQuadsByPrefix(QuadStore store, Term s, String pString, Term o, List prefices) {
        String preferredPrefix = prefices.get(0);
        Term realTerm;
        List quads = new ArrayList<>();
        for (int i = 0; i < prefices.size(); i++) {
            realTerm = new NamedNode(prefices.get(i) + pString);
            quads = store.getQuads(s, realTerm, o);
            if (quads.size() > 0) {
                if (i != 0) {
                    logger.warn(prefices.get(i) + "is a deprecated prefix, please use " + preferredPrefix);
                }
                return quads;
            }
        }
        return quads;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy