org.ut.biolab.medsavant.server.serverapi.AnnotationManager.java Source code

Java tutorial

Introduction

Here is the source code for org.ut.biolab.medsavant.server.serverapi.AnnotationManager.java

Source

/**
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This 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 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.ut.biolab.medsavant.server.serverapi;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.healthmarketscience.sqlbuilder.ComboCondition;
import com.healthmarketscience.sqlbuilder.DeleteQuery;
import com.healthmarketscience.sqlbuilder.InsertQuery;
import com.healthmarketscience.sqlbuilder.OrderObject.Dir;
import com.healthmarketscience.sqlbuilder.SelectQuery;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.ut.biolab.medsavant.server.db.MedSavantDatabase;
import org.ut.biolab.medsavant.server.db.MedSavantDatabase.AnnotationColumns;
import org.ut.biolab.medsavant.server.db.MedSavantDatabase.AnnotationFormatColumns;
import org.ut.biolab.medsavant.server.db.MedSavantDatabase.ReferenceTableSchema;
import org.ut.biolab.medsavant.server.db.MedSavantDatabase.VariantTablemapTableSchema;
import org.ut.biolab.medsavant.shared.db.TableSchema;
import org.ut.biolab.medsavant.server.db.ConnectionController;
import org.ut.biolab.medsavant.shared.format.AnnotationFormat;
import org.ut.biolab.medsavant.shared.format.AnnotationFormat.AnnotationType;
import org.ut.biolab.medsavant.shared.format.CustomField;
import org.ut.biolab.medsavant.shared.model.Annotation;
import org.ut.biolab.medsavant.shared.model.AnnotationDownloadInformation;
import org.ut.biolab.medsavant.server.MedSavantServerUnicastRemoteObject;
import org.ut.biolab.medsavant.server.db.PooledConnection;
import org.ut.biolab.medsavant.shared.model.SessionExpiredException;
import org.ut.biolab.medsavant.shared.serverapi.AnnotationManagerAdapter;
import org.ut.biolab.medsavant.shared.util.BinaryConditionMS;
import org.ut.biolab.medsavant.shared.util.DirectorySettings;
import org.ut.biolab.medsavant.shared.util.IOUtils;
import org.ut.biolab.medsavant.shared.util.NetworkUtils;

/**
 *
 * @author mfiume
 */
public class AnnotationManager extends MedSavantServerUnicastRemoteObject
        implements AnnotationManagerAdapter, AnnotationColumns {

    private static final Log LOG = LogFactory.getLog(AnnotationManager.class);
    private static AnnotationManager instance;

    private AnnotationManager() throws RemoteException, SessionExpiredException {
    }

    public static synchronized AnnotationManager getInstance() throws RemoteException, SessionExpiredException {
        if (instance == null) {
            instance = new AnnotationManager();
        }
        return instance;
    }

    @Override
    public boolean installAnnotationForProject(String sessionID, int currentProjectID, int transferID)
            throws RemoteException, SessionExpiredException, SQLException {
        try {
            LOG.info("Installing annotation transferred from client");
            NetworkManager netMgr = NetworkManager.getInstance();
            File annotationFile = netMgr.getFileByTransferID(sessionID, transferID);
            File installPath = generateInstallationDirectory();
            LOG.info("Installing to " + installPath.getAbsolutePath());
            /* Path p = Paths.get(annotationFile.getAbsolutePath());
             String fn = p.getFileName().toString();
             File newDestination = new File(installPath,fn);
             */
            File newPath = new File(installPath, "tmp.zip");
            LOG.info("Copy file to " + installPath.getAbsolutePath());
            IOUtils.copyFile(annotationFile, newPath); //annotationFile.renameTo(newDestination);

            LOG.info("Unzipping file");
            unpackAnnotationZip(newPath);

            LOG.info("Touching done file");
            File doneFile = new File(installPath, "installed.touch");
            doneFile.createNewFile();

            //return registerAnnotationWithProject(installPath, sessionID);
            return (registerAnnotationWithProject(installPath, sessionID) >= 0);

        } catch (Exception ex) {
            LOG.error("Problem installing annotation", ex);
            ex.printStackTrace();
            //return -1;
            return false;
        }

    }

    @Override
    public boolean installAnnotationForProject(String sessID, int projectID, AnnotationDownloadInformation info) {
        return (doInstallAnnotationForProject(sessID, projectID, info) >= 0);
    }

    public int doInstallAnnotationForProject(String sessID, int projectID, AnnotationDownloadInformation info) {

        try {
            // if it's not installed
            int i = getInstalledAnnotationID(sessID, info);
            if (i < 0) {
                LOG.info("Installing annotation " + info);
                // is it already downloaded?
                File installPath = generateInstallationDirectory();
                File doneFile = new File(installPath, "installed.touch");

                LOG.info("Checking for successful installation at " + installPath.getAbsolutePath());

                if (!doneFile.exists()) {

                    File downloadPath = new File(installPath, "tmp.zip");
                    LOG.info("Downloading annotation, be patient...");
                    downloadAnnotation(info, downloadPath);
                    LOG.info("Registering annotation to project");
                    unpackAnnotationZip(downloadPath);
                    doneFile.createNewFile();

                } else {
                    LOG.info("Annotation files already on disk");
                }

                i = registerAnnotationWithProject(installPath, sessID);

                LOG.info("Done installing annotation");
            }
            return i;
        } catch (Exception ex) {
            LOG.error("Problem installing annotation", ex);
            return -1;
        }
    }

    /*
     private static void installZipForProject(String sessionID, int projectID, File zip) throws IOException, ParserConfigurationException, SAXException, SQLException, SessionExpiredException {
     LOG.info("Installing zip...");
     File dir = unpackAnnotationZip(zip);
     LOG.info("... DONE");
        
        
     }
     */
    public static void addAnnotationFormat(String sessID, int annotID, int pos, String colName, String colType,
            boolean filterable, String alias, String desc, Set<String> tags)
            throws SQLException, SessionExpiredException {

        LOG.debug("Adding annotation format for " + colName);

        // remove non-alphanumeric characters from the proposed column name
        colName = colName.replaceAll("[^A-Za-z0-9]", "");

        String tagStr = "";
        for (String tag : tags) {
            tagStr = "," + tag;
        }

        InsertQuery query = MedSavantDatabase.AnnotationFormatTableSchema.insert(ANNOTATION_ID, annotID,
                AnnotationFormatColumns.POSITION, pos, AnnotationFormatColumns.COLUMN_NAME, colName,
                AnnotationFormatColumns.COLUMN_TYPE, colType, AnnotationFormatColumns.FILTERABLE, filterable,
                AnnotationFormatColumns.ALIAS, alias, AnnotationFormatColumns.DESCRIPTION, desc,
                AnnotationFormatColumns.TAGS, ((tagStr.length() > 0) ? tagStr.substring(1) : ""));

        Connection c = ConnectionController.connectPooled(sessID);
        c.createStatement().executeUpdate(query.toString());
        c.close();
    }

    public static int addAnnotation(String sessID, String prog, String vers, int refID, String path, boolean hasRef,
            boolean hasAlt, int type, boolean endInclusive) throws SQLException, SessionExpiredException {

        LOG.debug("Adding annotation...");

        TableSchema table = MedSavantDatabase.AnnotationTableSchema;
        InsertQuery query = MedSavantDatabase.AnnotationTableSchema.insert(PROGRAM, prog, VERSION, vers,
                REFERENCE_ID, refID, PATH, path, HAS_REF, hasRef, HAS_ALT, hasAlt, TYPE, type, IS_END_INCLUSIVE,
                endInclusive);

        PooledConnection c = ConnectionController.connectPooled(sessID);
        PreparedStatement stmt = c.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
        stmt.execute();
        ResultSet res = stmt.getGeneratedKeys();
        res.next();

        int annotid = res.getInt(1);

        c.close();

        return annotid;
    }

    private static AnnotationFormat parseFormat(File tabixFile, File xmlFormatFile)
            throws SAXException, ParserConfigurationException, IOException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(xmlFormatFile);
        doc.getDocumentElement().normalize();

        boolean hasRef = doc.getDocumentElement().getAttribute("hasref").equals("true");
        boolean hasAlt = doc.getDocumentElement().getAttribute("hasalt").equals("true");
        boolean isEndInclusive = doc.getDocumentElement().getAttribute("isEndInclusive").isEmpty() ? false : true;
        String version = doc.getDocumentElement().getAttribute("version");
        String program = doc.getDocumentElement().getAttribute("program");
        String referenceName = doc.getDocumentElement().getAttribute("reference");
        AnnotationType annotationType = AnnotationFormat.AnnotationType
                .fromString(doc.getDocumentElement().getAttribute("type"));

        //String prefix = program + "_" + version.replaceAll("\\.", "_") + "_";

        //get custom columns
        NodeList fields = doc.getElementsByTagName("field");
        CustomField[] annotationFields = new CustomField[fields.getLength()];

        for (int i = 0; i < fields.getLength(); i++) {
            Element field = (Element) (fields.item(i));
            annotationFields[i] = new CustomField(field.getAttribute("name"), field.getAttribute("type"),
                    field.getAttribute("filterable").equals("true"), field.getAttribute("alias"),
                    field.getAttribute("description"), field.getAttribute("tags"), false);
        }

        return new AnnotationFormat(program, version, referenceName, tabixFile.getAbsolutePath(), hasRef, hasAlt,
                annotationType, isEndInclusive, annotationFields);
    }

    private static File unpackAnnotationZip(File zip) throws ZipException, IOException {
        IOUtils.unzipFile(zip, new File(zip.getAbsolutePath()).getParent());
        zip.delete();
        return new File(new File(zip.getAbsolutePath()).getParent());
    }

    @Override
    public Annotation getAnnotation(String sid, int annotation_id) throws SQLException, SessionExpiredException {

        TableSchema refTable = MedSavantDatabase.ReferenceTableSchema;
        TableSchema annTable = MedSavantDatabase.AnnotationTableSchema;

        SelectQuery query = new SelectQuery();
        query.addFromTable(annTable.getTable());
        query.addAllColumns();
        query.addJoin(SelectQuery.JoinType.LEFT_OUTER, annTable.getTable(), refTable.getTable(),
                BinaryConditionMS.equalTo(annTable.getDBColumn(REFERENCE_ID),
                        refTable.getDBColumn(ReferenceTableSchema.COLUMNNAME_OF_REFERENCE_ID)));
        query.addCondition(BinaryConditionMS.equalTo(annTable.getDBColumn(ANNOTATION_ID), annotation_id));

        ResultSet rs = ConnectionController.executeQuery(sid, query.toString());

        rs.next();
        Annotation result = new Annotation(rs.getInt(ANNOTATION_ID.getColumnName()),
                rs.getString(PROGRAM.getColumnName()), rs.getString(VERSION.getColumnName()),
                rs.getInt(ReferenceTableSchema.COLUMNNAME_OF_REFERENCE_ID),
                rs.getString(ReferenceTableSchema.COLUMNNAME_OF_NAME), rs.getString(PATH.getColumnName()),
                AnnotationType.fromInt(rs.getInt(TYPE.getColumnName())),
                rs.getBoolean(IS_END_INCLUSIVE.getColumnName()));

        return result;
    }

    @Override
    public Annotation[] getAnnotations(String sid) throws SQLException, SessionExpiredException {

        TableSchema refTable = MedSavantDatabase.ReferenceTableSchema;
        TableSchema annTable = MedSavantDatabase.AnnotationTableSchema;

        SelectQuery query = new SelectQuery();
        query.addFromTable(annTable.getTable());
        query.addAllColumns();
        query.addJoin(SelectQuery.JoinType.LEFT_OUTER, annTable.getTable(), refTable.getTable(),
                BinaryConditionMS.equalTo(annTable.getDBColumn(REFERENCE_ID),
                        refTable.getDBColumn(ReferenceTableSchema.COLUMNNAME_OF_REFERENCE_ID)));

        ResultSet rs = ConnectionController.executeQuery(sid, query.toString());

        List<Annotation> result = new ArrayList<Annotation>();

        while (rs.next()) {
            result.add(new Annotation(rs.getInt(ANNOTATION_ID.getColumnName()),
                    rs.getString(PROGRAM.getColumnName()), rs.getString(VERSION.getColumnName()),
                    rs.getInt(ReferenceTableSchema.COLUMNNAME_OF_REFERENCE_ID),
                    rs.getString(ReferenceTableSchema.COLUMNNAME_OF_NAME), rs.getString(PATH.getColumnName()),
                    AnnotationType.fromInt(rs.getInt(TYPE.getColumnName())),
                    rs.getBoolean(IS_END_INCLUSIVE.getColumnName())));
        }

        return result.toArray(new Annotation[0]);
    }

    /*
     * Get the annotation ids associated with the latest published table.
     */
    @Override
    public int[] getAnnotationIDs(String sessID, int projID, int refID)
            throws SQLException, SessionExpiredException {

        TableSchema table = MedSavantDatabase.VarianttablemapTableSchema;
        SelectQuery query = new SelectQuery();
        query.addFromTable(table.getTable());
        query.addColumns(table.getDBColumn(VariantTablemapTableSchema.COLUMNNAME_OF_ANNOTATION_IDS));
        query.addCondition(ComboCondition.and(
                BinaryConditionMS.equalTo(table.getDBColumn(VariantTablemapTableSchema.COLUMNNAME_OF_PROJECT_ID),
                        projID),
                BinaryConditionMS.equalTo(table.getDBColumn(VariantTablemapTableSchema.COLUMNNAME_OF_REFERENCE_ID),
                        refID),
                BinaryConditionMS.equalTo(table.getDBColumn(VariantTablemapTableSchema.COLUMNNAME_OF_PUBLISHED),
                        true)));
        query.addOrdering(table.getDBColumn(VariantTablemapTableSchema.COLUMNNAME_OF_UPDATE_ID), Dir.DESCENDING);

        String a = query.toString();
        ResultSet rs = ConnectionController.executeQuery(sessID, query.toString());

        if (!rs.next()) {
            return new int[0];
        }

        String annotationString = rs.getString(VariantTablemapTableSchema.COLUMNNAME_OF_ANNOTATION_IDS);

        if (annotationString == null || annotationString.isEmpty()) {
            return new int[0];
        }

        String[] split = annotationString.split(",");
        int[] result = new int[split.length];
        for (int i = 0; i < split.length; i++) {
            result[i] = Integer.parseInt(split[i]);
        }

        return result;
    }

    @Override
    public AnnotationFormat[] getAnnotationFormats(String sessID, int projectID, int refID)
            throws SQLException, RemoteException, SessionExpiredException {
        int[] annotationIDs = getAnnotationIDs(sessID, projectID, refID);
        AnnotationFormat[] annotationFormats = new AnnotationFormat[annotationIDs.length];
        int i = 0;
        for (int annotationId : annotationIDs) {
            annotationFormats[i] = getAnnotationFormat(sessID, annotationId);
            i++;
        }
        return annotationFormats;
    }

    @Override
    public AnnotationFormat getAnnotationFormat(String sessID, int annotID)
            throws SQLException, RemoteException, SessionExpiredException {

        TableSchema annTable = MedSavantDatabase.AnnotationTableSchema;
        SelectQuery query1 = new SelectQuery();
        query1.addFromTable(annTable.getTable());
        query1.addAllColumns();
        query1.addCondition(BinaryConditionMS.equalTo(annTable.getDBColumn(ANNOTATION_ID), annotID));

        ResultSet rs1 = ConnectionController.executeQuery(sessID, query1.toString());

        rs1.next();

        String program = rs1.getString(PROGRAM.getColumnName());
        String version = rs1.getString(VERSION.getColumnName());
        String referenceName = ReferenceManager.getInstance().getReferenceName(sessID,
                rs1.getInt(REFERENCE_ID.getColumnName()));
        String path = rs1.getString(PATH.getColumnName());
        boolean hasRef = rs1.getBoolean(HAS_REF.getColumnName());
        boolean hasAlt = rs1.getBoolean(HAS_ALT.getColumnName());
        boolean isEndInclusive = rs1.getBoolean(IS_END_INCLUSIVE.getColumnName());
        AnnotationType type = AnnotationType.fromInt(rs1.getInt(TYPE.getColumnName()));

        TableSchema annFormatTable = MedSavantDatabase.AnnotationFormatTableSchema;
        SelectQuery query2 = new SelectQuery();
        query2.addFromTable(annFormatTable.getTable());
        query2.addAllColumns();
        query2.addCondition(BinaryConditionMS
                .equalTo(annFormatTable.getDBColumn(AnnotationFormatColumns.ANNOTATION_ID), annotID));
        query2.addOrdering(annFormatTable.getDBColumn(AnnotationFormatColumns.POSITION), Dir.ASCENDING);

        ResultSet rs2 = ConnectionController.executeQuery(sessID, query2.toString());

        List<CustomField> fields = new ArrayList<CustomField>();
        while (rs2.next()) {
            fields.add(new CustomField(rs2.getString(AnnotationFormatColumns.COLUMN_NAME.getColumnName()),
                    rs2.getString(AnnotationFormatColumns.COLUMN_TYPE.getColumnName()),
                    rs2.getBoolean(AnnotationFormatColumns.FILTERABLE.getColumnName()),
                    rs2.getString(AnnotationFormatColumns.ALIAS.getColumnName()),
                    rs2.getString(AnnotationFormatColumns.DESCRIPTION.getColumnName()),
                    rs2.getString(AnnotationFormatColumns.TAGS.getColumnName()), false)); //not null = false so that nulls represent missing values.
        }

        return new AnnotationFormat(program, version, referenceName, path, hasRef, hasAlt, type, isEndInclusive,
                fields.toArray(new CustomField[0]));
    }

    /**
     * HELPER FUNCTIONS
     */
    private static final File localDirectory = new File(DirectorySettings.getMedSavantDirectory() + "/annotation");

    public static void printFile(File f) throws FileNotFoundException, IOException {
        BufferedReader br = new BufferedReader(new FileReader(f));
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }

    /*
     private static File getZipLocation(AnnotationDownloadInformation adi) {
        
     File targetDir = getInstallationDirectory(adi.getProgramName(), adi.getProgramVersion(), adi.getReference());
     String targetFileName = "tmp.zip";
        
     return new File(targetDir, targetFileName);
     }
     */
    public static void downloadAnnotation(AnnotationDownloadInformation adi, File location)
            throws MalformedURLException, IOException {

        URL u = new URL(adi.getURL());
        File targetDir = location.getParentFile();
        targetDir.mkdirs();
        String targetFilename = location.getName();

        LOG.debug(
                "Downloading " + u.toString() + " to " + ((new File(targetDir, targetFilename).getAbsolutePath())));

        NetworkUtils.downloadFile(u, targetDir, targetFilename);

    }

    /**
     * Get the prescribed directory for the given annotation
     *
     * @param info The annotation whose directory is to be returned
     * @return The directory
     */
    private static File getDirectoryForAnnotation(AnnotationDownloadInformation info) {
        return getDirectoryForAnnotation(info.getProgramName(), info.getProgramVersion(), info.getReference());
    }

    /**
     * Get the prescribed directory for the given annotation
     *
     * @param programName The program name for this annotation
     * @param programVersion The program version for this annotation
     * @param reference The genome reference that this annotation applies to
     * @return
     */
    private static File getDirectoryForAnnotation(String programName, String programVersion, String reference) {

        return new File(
                localDirectory.getAbsolutePath() + "/" + reference + "/" + programName + "/" + programVersion);
    }

    /**
     * Get the expected location of the Tabix file
     *
     * @param dir The directory
     * @return The expected location of the Tabix file
     */
    private static File getTabixFile(File dir) {
        //return new File(dir + "/annotation.gz");
        return getFileWithExtentionInDir(dir, "gz");
    }

    /**
     * Get the expected location of the Tabix index file
     *
     * @param dir The directory
     * @return The expected location of the Tabix index file
     */
    private static File getTabixIndexFile(File dir) {
        //return new File(dir + "/annotation.tbi");
        return getFileWithExtentionInDir(dir, "tbi");
    }

    /**
     * Get the expected location of the format file
     *
     * @param dir The directory
     * @return The expected location of the format file
     */
    private static File getFormatFile(File dir) {
        return getFileWithExtentionInDir(dir, "xml");
    }

    private static File getFileWithExtentionInDir(File dir, final String ext) {
        return dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                if (name.endsWith("." + ext)) {
                    return true;
                }
                return false;
            }
        })[0];
    }

    /**
     * Checks that the annotation is installed
     *
     * @param info The Annotation information (version,reference,etc) for the
     * annotation to check
     * @return The id of the annotation if it is installed, -1 otherwise.
     */
    private int getInstalledAnnotationID(String sessID, AnnotationDownloadInformation info)
            throws RemoteException, SQLException, SessionExpiredException {

        TableSchema table = MedSavantDatabase.AnnotationTableSchema;
        SelectQuery query1 = new SelectQuery();
        query1.addFromTable(table.getTable());
        query1.addAllColumns();
        query1.addCondition(
                ComboCondition.and(BinaryConditionMS.equalTo(table.getDBColumn(PROGRAM), info.getProgramName()),
                        BinaryConditionMS.equalTo(table.getDBColumn(VERSION), info.getProgramVersion()),
                        BinaryConditionMS.equalTo(table.getDBColumn(REFERENCE_ID),
                                ReferenceManager.getInstance().getReferenceID(sessID, info.getReference()))));

        ResultSet rs1 = ConnectionController.executeQuery(sessID, query1.toString());

        // true if there is a match and false otherwise
        if (rs1.next()) {
            return rs1.getInt("annotation_id");
        } else {
            return -1;
        }
    }

    @Override
    public void uninstallAnnotation(String sessionID, int annotationID)
            throws RemoteException, SQLException, SessionExpiredException {

        File installationPath = getInstallationDirectoryFromID(sessionID, annotationID);

        TableSchema table = MedSavantDatabase.AnnotationTableSchema;

        DeleteQuery query1 = new DeleteQuery(table.getTable());
        query1.addCondition(BinaryConditionMS.equalTo(table.getDBColumn(ANNOTATION_ID), annotationID));
        ConnectionController.executeUpdate(sessionID, query1.toString());

        TableSchema table2 = MedSavantDatabase.AnnotationFormatTableSchema;

        DeleteQuery query2 = new DeleteQuery(table2.getTable());
        query2.addCondition(BinaryConditionMS.equalTo(table.getDBColumn(ANNOTATION_ID), annotationID));
        ConnectionController.executeUpdate(sessionID, query2.toString());

        try {
            Process p = Runtime.getRuntime().exec("chmod -R o+w " + installationPath.getAbsolutePath());
            p.waitFor();
        } catch (Exception e) {
        }
        deleteDirectory(installationPath);
    }

    /**
     * Force deletion of directory
     *
     * @param path
     * @return
     */
    static public boolean deleteDirectory(File path) {
        if (path.exists()) {
            File[] files = path.listFiles();
            for (int i = 0; i < files.length; i++) {
                if (files[i].isDirectory()) {
                    deleteDirectory(files[i]);
                } else {
                    files[i].delete();
                }
            }
        }
        return (path.delete());
    }

    private static File generateInstallationDirectory() {
        int i = 1;
        File dir;
        while (true) {
            dir = new File(localDirectory.getAbsolutePath(), i + "");
            if (!dir.exists()) {
                LOG.info("Creating installation directory: " + dir.getAbsolutePath());
                if (!dir.mkdirs()) {
                    LOG.error("Couldn't create installation directory for annotation: " + dir.getAbsolutePath());
                }
                return dir;
            }
            i++;
        }
        //return new File(localDirectory.getAbsolutePath() + "/" + programName + "_" + version + "_" + reference);
    }

    private static int registerAnnotationWithProject(File dir, String sessionID) throws RemoteException,
            SAXException, SQLException, IOException, ParserConfigurationException, SessionExpiredException {
        LOG.info("Parsing format...");
        AnnotationFormat format = parseFormat(getTabixFile(dir), getFormatFile(dir));
        LOG.info("... DONE");

        LOG.info("FORMAT: " + format);

        int id = addAnnotation(sessionID, format.getProgram(), format.getVersion(),
                ReferenceManager.getInstance().getReferenceID(sessionID, format.getReferenceName()),
                getTabixFile(dir).getAbsolutePath(), format.hasRef(), format.hasAlt(),
                AnnotationType.toInt(format.getType()), format.isEndInclusive());

        //populate
        Connection conn = ConnectionController.connectPooled(sessionID);
        conn.setAutoCommit(false);

        int i = 0;
        for (CustomField a : format.getCustomFields()) {
            addAnnotationFormat(sessionID, id, i++, id + "_" + a.getColumnName(), a.getTypeString(),
                    a.isFilterable(), a.getAlias(), a.getDescription(), a.getTags());
        }
        conn.commit();
        conn.setAutoCommit(true);
        conn.close();

        LOG.info("Installed to " + dir.getAbsolutePath());
        return id;
    }

    private File getInstallationDirectoryFromID(String sessID, int annotationID)
            throws SQLException, SessionExpiredException {

        TableSchema table = MedSavantDatabase.AnnotationTableSchema;
        SelectQuery query1 = new SelectQuery();
        query1.addFromTable(table.getTable());
        query1.addColumns(table.getDBColumn(PATH));
        query1.addCondition(BinaryConditionMS.equalTo(table.getDBColumn(ANNOTATION_ID), annotationID));

        LOG.info(query1.toString());

        ResultSet rs1 = ConnectionController.executeQuery(sessID, query1.toString());

        if (rs1.next()) {
            String path = rs1.getString(1);

            LOG.info("Path to installation directory is " + path);

            File f = new File(path);

            if (!f.isDirectory()) {
                f = f.getParentFile();
            }
            return f;
        } else {
            LOG.info("Error getting path to installation directory for annotation with ID " + annotationID);

            return null;
        }

    }

    @Override
    public Set<String> getAnnotationTags(String sessID)
            throws SQLException, RemoteException, SessionExpiredException {
        TableSchema annFormatTable = MedSavantDatabase.AnnotationFormatTableSchema;
        SelectQuery query2 = new SelectQuery();
        query2.addFromTable(annFormatTable.getTable());
        query2.addColumns(annFormatTable.getDBColumn(AnnotationFormatColumns.TAGS.getColumnName()));
        query2.setIsDistinct(true);

        ResultSet rs2 = ConnectionController.executeQuery(sessID, query2.toString());

        Set<String> tags = new HashSet<String>();
        while (rs2.next()) {
            String tagStr = rs2.getString(AnnotationFormatColumns.TAGS.getColumnName());
            String[] tagArray = tagStr.split(CustomField.TAG_DELIMITER);
            for (String tag : tagArray) {
                tags.add(tag);
            }
        }
        rs2.close();
        return tags;
    }

    @Override
    public Map<String, Set<CustomField>> getAnnotationFieldsByTag(String sessionId, boolean includeUndefined)
            throws SQLException, RemoteException, SessionExpiredException {
        final String UNDEFINED_TAG = "UNDEFINED"; //do not change

        Map<String, Set<CustomField>> amap = new HashMap<String, Set<CustomField>>();

        Annotation[] annotations = getAnnotations(sessionId);
        for (Annotation annotation : annotations) {
            AnnotationFormat af = getAnnotationFormat(sessionId, annotation.getID());
            CustomField[] customFields = af.getCustomFields();
            for (CustomField customField : customFields) {
                Set<String> tags = customField.getTags();
                if (tags.isEmpty() && includeUndefined) {
                    tags.add(UNDEFINED_TAG);
                }
                for (String tag : tags) {
                    Set<CustomField> cs = amap.get(tag);
                    if (cs == null) {
                        cs = new HashSet<CustomField>();
                    }
                    cs.add(customField);
                    amap.put(tag, cs);
                }

            }
        }
        return amap;
    }
}