au.org.ands.vocabs.toolkit.db.AccessPointUtils.java Source code

Java tutorial

Introduction

Here is the source code for au.org.ands.vocabs.toolkit.db.AccessPointUtils.java

Source

/** See the file "LICENSE" for the full license governing this code. */
package au.org.ands.vocabs.toolkit.db;

import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;

import javax.json.Json;
import javax.json.JsonObjectBuilder;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;

import au.org.ands.vocabs.toolkit.db.model.AccessPoint;
import au.org.ands.vocabs.toolkit.db.model.Version;
import au.org.ands.vocabs.toolkit.restlet.Download;
import au.org.ands.vocabs.toolkit.utils.PropertyConstants;
import au.org.ands.vocabs.toolkit.utils.ToolkitProperties;

/** Work with database access points. */
public final class AccessPointUtils {

    /** Logger for this class. */
    private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    /** Access to the Toolkit properties. */
    protected static final Properties PROPS = ToolkitProperties.getProperties();

    /** URL that is a prefix to download endpoints. */
    private static String downloadPrefixProperty = PROPS.getProperty(PropertyConstants.TOOLKIT_DOWNLOADPREFIX);

    /** Mapping of file extensions to file formats. */
    public static final Hashtable<String, String> EXTENSION_TO_FILE_FORMAT_MAP = new Hashtable<String, String>();

    /** Mapping of MIME types to file formats. */
    public static final Hashtable<String, String> MIMETYPE_TO_FILE_FORMAT_MAP = new Hashtable<String, String>();

    // The values should match those in:
    // ANDS-Registry-Core/applications/portal/vocabs/assets/js/versionCtrl.js
    static {
        EXTENSION_TO_FILE_FORMAT_MAP.put("rdf", "RDF/XML");
        EXTENSION_TO_FILE_FORMAT_MAP.put("ttl", "TTL");
        EXTENSION_TO_FILE_FORMAT_MAP.put("nt", "N-Triples");
        EXTENSION_TO_FILE_FORMAT_MAP.put("json", "JSON");
        EXTENSION_TO_FILE_FORMAT_MAP.put("trig", "TriG");
        EXTENSION_TO_FILE_FORMAT_MAP.put("trix", "TriX");
        EXTENSION_TO_FILE_FORMAT_MAP.put("n3", "N3");
        EXTENSION_TO_FILE_FORMAT_MAP.put("csv", "CSV");
        EXTENSION_TO_FILE_FORMAT_MAP.put("tsv", "TSV");
        EXTENSION_TO_FILE_FORMAT_MAP.put("xls", "XLS");
        EXTENSION_TO_FILE_FORMAT_MAP.put("xlsx", "XLSX");
        EXTENSION_TO_FILE_FORMAT_MAP.put("ods", "ODS");
        EXTENSION_TO_FILE_FORMAT_MAP.put("zip", "ZIP");
        EXTENSION_TO_FILE_FORMAT_MAP.put("xml", "XML");
        EXTENSION_TO_FILE_FORMAT_MAP.put("txt", "TXT");
        EXTENSION_TO_FILE_FORMAT_MAP.put("odt", "ODT");
        //        EXTENSION_TO_FILE_FORMAT_MAP.put("", "");

        //        EXTENSION_TO_FILE_FORMAT_MAP.put("nq", "NQ");
    }

    // The values should match those in:
    // ANDS-Registry-Core/applications/portal/vocabs/assets/js/versionCtrl.js
    static {
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/rdf+xml", "RDF/XML");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/turtle", "TTL");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/plain", "N-Triples");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/json", "JSON");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/x-trig", "TriG");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/trix", "TriX");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/rdf+n3", "N3");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/csv", "CSV");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/csv", "TSV");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/vnd.ms-excel", "XLS");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/vnd.openxmlformats-officedocument." + "spreadsheetml.sheet",
                "XLSX");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/x-binary-rdf", "BinaryRDF");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/vnd.oasis.opendocument.spreadsheet", "ODS");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/zip", "ZIP");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/xml", "XML");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/plain", "TXT");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/vnd.oasis.opendocument.text", "ODT");
        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/plain", "TEXT");
        //        MIMETYPE_TO_FILE_FORMAT_MAP.put("", "");

        //        MIMETYPE_TO_FILE_FORMAT_MAP.put("text/x-nquads", "nq");
        //        MIMETYPE_TO_FILE_FORMAT_MAP.put("application/rdf+json", "json");
    }

    /** Private constructor for a utility class. */
    private AccessPointUtils() {
    }

    /** Get all access points.
     * @return A list of AccessPoints
     */
    public static List<AccessPoint> getAllAccessPoints() {
        EntityManager em = DBContext.getEntityManager();
        TypedQuery<AccessPoint> query = em.createNamedQuery(AccessPoint.GET_ALL_ACCESSPOINTS, AccessPoint.class);
        List<AccessPoint> aps = query.getResultList();
        em.close();
        return aps;
    }

    /** Get access point by access point id.
     * @param id access point id
     * @return the access point
     */
    public static AccessPoint getAccessPointById(final int id) {
        EntityManager em = DBContext.getEntityManager();
        AccessPoint ap = em.find(AccessPoint.class, id);
        em.close();
        return ap;
    }

    /** Get all access points for a version.
     * @param version The version.
     * @return The list of access points for this version.
     */
    public static List<AccessPoint> getAccessPointsForVersion(final Version version) {
        EntityManager em = DBContext.getEntityManager();
        TypedQuery<AccessPoint> q = em.createNamedQuery(AccessPoint.GET_ACCESSPOINTS_FOR_VERSION, AccessPoint.class)
                .setParameter(AccessPoint.GET_ACCESSPOINTS_FOR_VERSION_VERSIONID, version.getId());
        List<AccessPoint> aps = q.getResultList();
        em.close();
        return aps;
    }

    /** Get all access points of a certain type for a version.
     * @param version The version.
     * @param type The type of access point to look for.
     * @return The list of access points for this version.
     */
    public static List<AccessPoint> getAccessPointsForVersionAndType(final Version version, final String type) {
        EntityManager em = DBContext.getEntityManager();
        TypedQuery<AccessPoint> q = em
                .createNamedQuery(AccessPoint.GET_ACCESSPOINTS_FOR_VERSION_AND_TYPE, AccessPoint.class)
                .setParameter(AccessPoint.GET_ACCESSPOINTS_FOR_VERSION_AND_TYPE_VERSIONID, version.getId())
                .setParameter(AccessPoint.GET_ACCESSPOINTS_FOR_VERSION_AND_TYPE_TYPE, type);
        List<AccessPoint> aps = q.getResultList();
        em.close();
        return aps;
    }

    /** Delete all access points of a certain type for a version.
     * @param version The version.
     * @param type The type of access point to look for.
     */
    public static void deleteAccessPointsForVersionAndType(final Version version, final String type) {
        EntityManager em = DBContext.getEntityManager();
        em.getTransaction().begin();
        Query q = em.createNamedQuery(AccessPoint.DELETE_ACCESSPOINTS_FOR_VERSION_AND_TYPE)
                .setParameter(AccessPoint.DELETE_ACCESSPOINTS_FOR_VERSION_AND_TYPE_VERSIONID, version.getId())
                .setParameter(AccessPoint.DELETE_ACCESSPOINTS_FOR_VERSION_AND_TYPE_TYPE, type);
        q.executeUpdate();
        em.getTransaction().commit();
        em.close();
    }

    /** Get the portal's format setting for a file access point.
     * @param ap the access point
     * @return the access point's format setting, if it has one,
     * or null otherwise.
     */
    public static String getFormat(final AccessPoint ap) {
        if (!"file".equals(ap.getType())) {
            // Not the right type.
            return null;
        }
        JsonNode dataJson = TaskUtils.jsonStringToTree(ap.getPortalData());
        JsonNode format = dataJson.get("format");
        if (format == null) {
            return null;
        }
        return format.asText();
    }

    /** Update the portal's format setting for a file access point.
     * @param ap the access point
     * @param newFormat the access point's new format setting,
     * or null otherwise.
     */
    public static void updateFormat(final AccessPoint ap, final String newFormat) {
        if (!"file".equals(ap.getType())) {
            // Not the right type.
            return;
        }
        JsonNode dataJson = TaskUtils.jsonStringToTree(ap.getPortalData());
        JsonObjectBuilder jobPortal = Json.createObjectBuilder();
        Iterator<Entry<String, JsonNode>> dataJsonIterator = dataJson.fields();
        while (dataJsonIterator.hasNext()) {
            Entry<String, JsonNode> entry = dataJsonIterator.next();
            jobPortal.add(entry.getKey(), entry.getValue().asText());
        }
        jobPortal.add("format", newFormat);
        ap.setPortalData(jobPortal.build().toString());
        updateAccessPoint(ap);
    }

    /** Get the Toolkit's path setting for a file access point.
     * @param ap the access point
     * @return the access point's file setting, if it has one,
     * or null otherwise.
     */
    public static String getToolkitPath(final AccessPoint ap) {
        if (!"file".equals(ap.getType())) {
            // Not the right type.
            return null;
        }
        JsonNode dataJson = TaskUtils.jsonStringToTree(ap.getToolkitData());
        JsonNode path = dataJson.get("path");
        if (path == null) {
            return null;
        }
        return path.asText();
    }

    /** Get the portal's uri setting for an apiSparql or sissvoc access point.
     * @param ap the access point
     * @return the access point's portal uri setting, if it has one,
     * or null otherwise.
     */
    public static String getPortalUri(final AccessPoint ap) {
        if (!(AccessPoint.API_SPARQL_TYPE.equals(ap.getType())
                || (AccessPoint.SISSVOC_TYPE.equals(ap.getType())))) {
            // Not the right type.
            return null;
        }
        JsonNode dataJson = TaskUtils.jsonStringToTree(ap.getPortalData());
        JsonNode uri = dataJson.get("uri");
        if (uri == null) {
            return null;
        }
        return uri.asText();
    }

    /** Get the Toolkit's uri setting for a sesameDownload access point.
     * @param ap the access point
     * @return the access point's Toolkit uri setting, if it has one,
     * or null otherwise.
     */
    public static String getToolkitUri(final AccessPoint ap) {
        if (!AccessPoint.SESAME_DOWNLOAD_TYPE.equals(ap.getType())) {
            // Not the right type.
            return null;
        }
        JsonNode dataJson = TaskUtils.jsonStringToTree(ap.getToolkitData());
        JsonNode uri = dataJson.get("uri");
        if (uri == null) {
            return null;
        }
        return uri.asText();
    }

    /** Save a new access point to the database.
     * @param ap The access point to be saved.
     */
    public static void saveAccessPoint(final AccessPoint ap) {
        EntityManager em = DBContext.getEntityManager();
        em.getTransaction().begin();
        em.persist(ap);
        em.getTransaction().commit();
        em.close();
    }

    /** Update an existing access point in the database.
     * @param ap The access point to be update.
     */
    public static void updateAccessPoint(final AccessPoint ap) {
        EntityManager em = DBContext.getEntityManager();
        em.getTransaction().begin();
        em.merge(ap);
        em.getTransaction().commit();
        em.close();
    }

    /** Create an access point for a version, for a file. Don't duplicate it,
     * if it already exists.
     * @param version The version for which the access point is to be created.
     * @param format The format of the access point. If null, attempt
     * to deduce a format from the filename.
     * @param targetPath The path to the existing file.
     */
    public static void createFileAccessPoint(final Version version, final String format, final Path targetPath) {
        String targetPathString;
        try {
            targetPathString = targetPath.toRealPath().toString();
        } catch (IOException e) {
            LOGGER.error("createFileAccessPoint failed calling " + "toRealPath() on file: " + targetPath.toString(),
                    e);
            // Try toAbsolutePath() instead.
            targetPathString = targetPath.toAbsolutePath().toString();
        }
        List<AccessPoint> aps = getAccessPointsForVersionAndType(version, AccessPoint.FILE_TYPE);
        for (AccessPoint ap : aps) {
            if (targetPathString.equals(getToolkitPath(ap))) {
                // Already exists. Check the format.
                if (format != null && !format.equals(getFormat(ap))) {
                    // Format changed.
                    updateFormat(ap, format);
                }
                return;
            }
        }
        // No existing access point for this file, so create a new one.
        AccessPoint ap = new AccessPoint();
        ap.setVersionId(version.getId());
        ap.setType(AccessPoint.FILE_TYPE);
        JsonObjectBuilder jobPortal = Json.createObjectBuilder();
        JsonObjectBuilder jobToolkit = Json.createObjectBuilder();
        jobToolkit.add("path", targetPathString);
        // toolkitData is now done.
        ap.setToolkitData(jobToolkit.build().toString());
        ap.setPortalData("");
        // Persist what we have ...
        AccessPointUtils.saveAccessPoint(ap);
        // ... so that now we can get access to the
        // ID of the persisted object with ap.getId().
        String baseFilename = targetPath.getFileName().toString();
        jobPortal.add("uri", downloadPrefixProperty + ap.getId() + "/" + baseFilename);
        // Now work on the format. The following is messy. It's really very
        // much for the best if the portal provides the format.
        String deducedFormat;
        if (format == null) {
            // The format was not provided to us, so try to deduce it.
            // First, try the extension.
            String extension = FilenameUtils.getExtension(baseFilename);
            deducedFormat = EXTENSION_TO_FILE_FORMAT_MAP.get(extension);
            if (deducedFormat == null) {
                // No luck with the extension, so try probing.
                try {
                    String mimeType = Files.probeContentType(targetPath);
                    if (mimeType == null) {
                        // Give up.
                        deducedFormat = "Unknown";
                    } else {
                        deducedFormat = MIMETYPE_TO_FILE_FORMAT_MAP.get(mimeType);
                        if (deducedFormat == null) {
                            // Give up.
                            deducedFormat = "Unknown";
                        }
                    }
                } catch (IOException e) {
                    LOGGER.error("createFileAccessPoint failed to get " + "MIME type of file: " + targetPathString,
                            e);
                    // Give up.
                    deducedFormat = "Unknown";
                }
            }
        } else {
            // The format was provided to us, so use that. Much easier.
            deducedFormat = format;
        }
        jobPortal.add("format", deducedFormat);
        // portalData is now complete.
        ap.setPortalData(jobPortal.build().toString());
        AccessPointUtils.updateAccessPoint(ap);
    }

    /** Create an access point for a version, for a SPARQL endpoint.
     * Don't duplicate it, if it already exists.
     * @param version The version for which the access point is to be created.
     * @param portalUri The URI to put into the portalData.
     * @param source The source of the endpoint, either SYSTEM_SOURCE
     * or USER_SOURCE.
     */
    public static void createApiSparqlAccessPoint(final Version version, final String portalUri,
            final String source) {
        List<AccessPoint> aps = getAccessPointsForVersionAndType(version, AccessPoint.API_SPARQL_TYPE);
        for (AccessPoint ap : aps) {
            if (portalUri.equals(getPortalUri(ap))) {
                // Already exists. Don't bother checking the source.
                return;
            }
        }
        // No existing access point for this file, so create a new one.
        AccessPoint ap = new AccessPoint();
        ap.setVersionId(version.getId());
        ap.setType(AccessPoint.API_SPARQL_TYPE);
        JsonObjectBuilder jobPortal = Json.createObjectBuilder();
        JsonObjectBuilder jobToolkit = Json.createObjectBuilder();
        jobPortal.add("uri", portalUri);
        jobPortal.add("source", source);
        ap.setPortalData(jobPortal.build().toString());
        ap.setToolkitData(jobToolkit.build().toString());
        AccessPointUtils.saveAccessPoint(ap);
    }

    /** Create an access point for a version, for a Sesame download.
     * Don't duplicate it, if it already exists.
     * @param version The version for which the access point is to be created.
     * @param toolkitUri The URI to put into the toolkitData.
     */
    public static void createSesameDownloadAccessPoint(final Version version, final String toolkitUri) {
        List<AccessPoint> aps = getAccessPointsForVersionAndType(version, AccessPoint.SESAME_DOWNLOAD_TYPE);
        for (AccessPoint ap : aps) {
            if (toolkitUri.equals(getToolkitUri(ap))) {
                // Already exists.
                return;
            }
        }
        // No existing access point for this file, so create a new one.
        AccessPoint ap = new AccessPoint();
        ap.setVersionId(version.getId());
        ap.setType(AccessPoint.SESAME_DOWNLOAD_TYPE);
        ap.setPortalData("");
        JsonObjectBuilder jobToolkit = Json.createObjectBuilder();
        jobToolkit.add("uri", toolkitUri);
        ap.setToolkitData(jobToolkit.build().toString());
        // Persist what we have ...
        AccessPointUtils.saveAccessPoint(ap);
        // ... so that now we can get access to the
        // ID of the persisted object with ap.getId().
        JsonObjectBuilder jobPortal = Json.createObjectBuilder();
        jobPortal.add("uri", downloadPrefixProperty + ap.getId() + "/" + Download.downloadFilename(ap, ""));
        ap.setPortalData(jobPortal.build().toString());
        AccessPointUtils.updateAccessPoint(ap);
    }

    /** Create a sissvoc access point for a version.
     * Don't duplicate it, if it already exists.
     * @param version The version for which the access point is to be created.
     * @param portalUri The URI to put into the portalData.
     * @param source The source of the endpoint, either SYSTEM_SOURCE
     * or USER_SOURCE.
     */
    public static void createSissvocAccessPoint(final Version version, final String portalUri,
            final String source) {
        List<AccessPoint> aps = getAccessPointsForVersionAndType(version, AccessPoint.SISSVOC_TYPE);
        for (AccessPoint ap : aps) {
            if (portalUri.equals(getPortalUri(ap))) {
                // Already exists. Don't bother checking the source.
                return;
            }
        }
        // No existing access point for this file, so create a new one.
        AccessPoint ap = new AccessPoint();
        ap.setVersionId(version.getId());
        ap.setType(AccessPoint.SISSVOC_TYPE);
        JsonObjectBuilder jobPortal = Json.createObjectBuilder();
        JsonObjectBuilder jobToolkit = Json.createObjectBuilder();
        jobPortal.add("uri", portalUri);
        jobPortal.add("source", source);
        ap.setPortalData(jobPortal.build().toString());
        ap.setToolkitData(jobToolkit.build().toString());
        AccessPointUtils.saveAccessPoint(ap);
    }

}