net.psexton.libuti.UtiDb.java Source code

Java tutorial

Introduction

Here is the source code for net.psexton.libuti.UtiDb.java

Source

/*
 * This file is part of LibUti.
 * 
 * LibUti is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * LibUti is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with LibUti. If not, see <http://www.gnu.org/licenses/>.
 */
package net.psexton.libuti;

import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

/**
 * Database for UTIs
 * @author psexton
 */
public class UtiDb {
    // Singleton stuff
    private static class SingletonHolder {
        public static final UtiDb instance = new UtiDb(true);
    }

    /**
     * Singleton accessor for UTI Database.
     * @return Instance of UtiDb
     */
    public static UtiDb getInstance() {
        return SingletonHolder.instance;
    }

    static UtiDb getCleanInstance() {
        return new UtiDb(false);
    } // used by unit tests
    // End Singleton stuff

    private final Map<String, String> suffixTable;
    private final Map<String, String> reverseSuffixTable;
    private final DirectedSparseGraph<String, String> conformances;

    private UtiDb(boolean loadStandardData) {
        suffixTable = new HashMap<>();
        reverseSuffixTable = new HashMap<>();
        conformances = new DirectedSparseGraph<>();
        if (loadStandardData) {
            String[] dataFiles = { "Archive", "Audio", "Image", "Matlab", "MicrosoftOffice", "Other",
                    "RootsAndBases", "Text", "Video" };
            for (String dataFile : dataFiles) {
                try {
                    importXmlData(
                            this.getClass().getResourceAsStream("/net/psexton/libuti/data/" + dataFile + ".xml"));
                } catch (IOException | JDOMException ex) {
                    Logger.getLogger(UtiDb.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    /**
     * Adds UTI mappings to the DB from an XML source
     * @param in InputStream containing XML data
     * @throws IOException if there was a problem reading the InputStream
     * @throws JDOMException if there was a problem parsing the XML
     */
    public final void importXmlData(InputStream in) throws IOException, JDOMException {
        // Parse the input stream and rip out a usable Element from the Document
        Document doc = new SAXBuilder().build(in);
        Element root = doc.detachRootElement();

        // root element is <uti-list>
        // Iterate over all <uti> children
        for (Object o : root.getChildren("uti")) {
            Element uti = (Element) o;
            // UTI's name is in a <name> child
            String name = uti.getChildText("name");
            conformances.addVertex(name); // Add UTI to graph
            // File suffixes are in <suffix> children
            // Iterate over them
            for (Object o2 : uti.getChildren("suffix")) {
                Element suffix = (Element) o2;
                if (suffix.getAttribute("preferred") != null
                        && suffix.getAttribute("preferred").getBooleanValue()) {
                    reverseSuffixTable.put(name, suffix.getText()); // Add UTI->suffix to reverseSuffixTable
                }
                suffixTable.put(suffix.getText(), name); // Add suffix->UTI to suffixTable
            }
            // Conformances are in <conforms-to> children
            // Iterate over them
            for (Object o2 : uti.getChildren("conforms-to")) {
                Element conformsTo = (Element) o2;
                String parentUtiName = conformsTo.getText();
                String edgeName = name + "->" + parentUtiName;
                conformances.addEdge(edgeName, name, parentUtiName, EdgeType.DIRECTED);
            }
        }
    }

    /**
     * Converts a file suffix to its UTI form.
     * @param suffix Three (or four or two) letter file extension
     * @return Name of matching UTI, or null
     */
    public String utiForSuffix(String suffix) {
        // Normalize suffix to lowercase checking
        // This is painfully non-I18N compatible, but it's better than nothing
        String normalizedSuffix = suffix.toLowerCase();

        if (suffixTable.containsKey(normalizedSuffix))
            return suffixTable.get(normalizedSuffix);
        else
            return null;
    }

    /**
     * Reverse mapping of UTI to preferred file suffix.
     * @param uti String form of a UTI
     * @return Preferred file extension, or null
     */
    public String preferredSuffixForUti(String uti) {
        if (reverseSuffixTable.containsKey(uti))
            return reverseSuffixTable.get(uti);
        else
            return null;
    }

    /**
     * Checks if the specified UTI name is found in the DB
     * @param utiName UTI name to search for
     * @return True if found, false if not
     */
    public Boolean isUtiInDb(String utiName) {
        return conformances.containsVertex(utiName);
    }

    /**
     * Checks if one UTI conforms to another.
     * @param childUti The conforming UTI.
     * @param parentUti The UTI being conformed to.
     * @return True if the conformance relation exists.
     */
    public Boolean conformsTo(String childUti, String parentUti) {
        DijkstraShortestPath<String, String> alg = new DijkstraShortestPath<>(conformances);

        List<String> path = alg.getPath(childUti, parentUti);
        return !path.isEmpty();
    }

    /**
     * Full set of conformances.
     * Returns a Set of all UTIs that the UTI passed in conforms to 
     * (including itself).
     * @param utiName UTI to look up.
     * @return Set of UTIs.
     */
    public Set<String> conformancesFor(String utiName) {
        Set<String> set = new HashSet<>();
        set.add(utiName); // always include self
        for (String successor : conformances.getSuccessors(utiName)) {
            Set<String> parentSet = conformancesFor(successor);
            set.addAll(parentSet);
        }

        return set;
    }

    /**
     * Full set of conformers.
     * Returns a Set of all UTIs that conform to the UTI passed in 
     * (including itself).
     * @param utiName UTI to look up.
     * @return Set of UTIs.
     */
    public Set<String> conformersFor(String utiName) {
        Set<String> set = new HashSet<>();
        set.add(utiName); // always include self
        for (String predecessor : conformances.getPredecessors(utiName)) {
            Set<String> childSet = conformersFor(predecessor);
            set.addAll(childSet);
        }

        return set;
    }

}