uk.ac.bbsrc.tgac.miso.core.util.LimsUtils.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.bbsrc.tgac.miso.core.util.LimsUtils.java

Source

/*
 * Copyright (c) 2012. The Genome Analysis Centre, Norwich, UK
 * MISO project contacts: Robert Davey @ TGAC
 * *********************************************************************
 *
 * This file is part of MISO.
 *
 * MISO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MISO 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 General Public License
 * along with MISO. If not, see <http://www.gnu.org/licenses/>.
 *
 * *********************************************************************
 */

package uk.ac.bbsrc.tgac.miso.core.util;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.hibernate.proxy.HibernateProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eaglegenomics.simlims.core.SecurityProfile;

import uk.ac.bbsrc.tgac.miso.core.data.Boxable;
import uk.ac.bbsrc.tgac.miso.core.data.DetailedLibrary;
import uk.ac.bbsrc.tgac.miso.core.data.DetailedSample;
import uk.ac.bbsrc.tgac.miso.core.data.IlluminaRun;
import uk.ac.bbsrc.tgac.miso.core.data.LS454Run;
import uk.ac.bbsrc.tgac.miso.core.data.Library;
import uk.ac.bbsrc.tgac.miso.core.data.Nameable;
import uk.ac.bbsrc.tgac.miso.core.data.OxfordNanoporeRun;
import uk.ac.bbsrc.tgac.miso.core.data.PacBioRun;
import uk.ac.bbsrc.tgac.miso.core.data.Run;
import uk.ac.bbsrc.tgac.miso.core.data.Sample;
import uk.ac.bbsrc.tgac.miso.core.data.SampleAliquot;
import uk.ac.bbsrc.tgac.miso.core.data.SampleIdentity;
import uk.ac.bbsrc.tgac.miso.core.data.SampleLCMTube;
import uk.ac.bbsrc.tgac.miso.core.data.SampleStock;
import uk.ac.bbsrc.tgac.miso.core.data.SampleTissue;
import uk.ac.bbsrc.tgac.miso.core.data.SampleTissueProcessing;
import uk.ac.bbsrc.tgac.miso.core.data.SequencerPartitionContainer;
import uk.ac.bbsrc.tgac.miso.core.data.SolidRun;
import uk.ac.bbsrc.tgac.miso.core.data.impl.LibraryDilution;
import uk.ac.bbsrc.tgac.miso.core.data.impl.OxfordNanoporeContainer;
import uk.ac.bbsrc.tgac.miso.core.security.SecurableByProfile;
import uk.ac.bbsrc.tgac.miso.core.service.naming.NamingScheme;
import uk.ac.bbsrc.tgac.miso.core.service.naming.validation.ValidationResult;

/**
 * Utility class to provde helpful functions to MISO
 * 
 * @author Rob Davey
 * @since 0.0.2
 */
public class LimsUtils {

    private static final Logger log = LoggerFactory.getLogger(LimsUtils.class);

    public static boolean isStringEmptyOrNull(String s) {
        return "".equals(s) || s == null;
    }

    public static boolean isStringBlankOrNull(String s) {
        return s == null || "".equals(s.trim());
    }

    public static String nullifyStringIfBlank(String s) {
        return (isStringBlankOrNull(s) ? null : s);
    }

    /**
     * Checks that a directory exists. This method will attempt to create the directory if it doesn't exist and if the attemptMkdir flag is
     * true
     * 
     * @param path of type File
     * @param attemptMkdir of type boolean
     * @return boolean true if the directory exists/was created, false if not
     * @throws IOException when the directory exist check/creation could not be completed
     */
    public static boolean checkDirectory(File path, boolean attemptMkdir) throws IOException {
        boolean storageOk;

        if (attemptMkdir) {
            storageOk = path.exists() || path.mkdirs();
        } else {
            storageOk = path.exists();
        }

        if (!storageOk) {
            StringBuilder sb = new StringBuilder("The directory [" + path.toString() + "] doesn't exist");
            if (attemptMkdir) {
                sb.append(" or is not creatable");
            }
            sb.append(". Please create this directory and ensure that it is writable.");
            throw new IOException(sb.toString());
        } else {
            if (attemptMkdir) {
                log.info("Directory (" + path + ") exists.");
            } else {
                log.info("Directory (" + path + ") OK.");
            }
        }
        return storageOk;
    }

    public static String getCurrentDateAsString(DateFormat df) {
        return df.format(new Date());
    }

    public static String getCurrentDateAsString() {
        return getCurrentDateAsString(new SimpleDateFormat("yyyyMMdd"));
    }

    public static String formatDate(Date date) {
        return date == null ? null : getDateFormat().format(date);
    }

    public static Date parseDate(String dateString) {
        if (isStringEmptyOrNull(dateString)) {
            return null;
        }
        try {
            return getDateFormat().parse(dateString);
        } catch (ParseException e) {
            throw new IllegalArgumentException("Invalid date string");
        }
    }

    public static String formatDateTime(Date date) {
        return date == null ? null : getDateTimeFormat().format(date);
    }

    public static Date parseDateTime(String dateString) {
        if (isStringEmptyOrNull(dateString)) {
            return null;
        }
        try {
            return getDateTimeFormat().parse(dateString);
        } catch (ParseException e) {
            throw new IllegalArgumentException("Invalid datetime string");
        }
    }

    public static DateFormat getDateFormat() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }

    public static DateFormat getDateTimeFormat() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }

    public static void inheritUsersAndGroups(SecurableByProfile child, SecurityProfile parentProfile) {
        SecurityProfile childProfile = child.getSecurityProfile();
        childProfile.setReadGroups(parentProfile.getReadGroups());
        childProfile.setWriteGroups(parentProfile.getWriteGroups());
        childProfile.setReadUsers(parentProfile.getReadUsers());
        childProfile.setWriteUsers(parentProfile.getWriteUsers());
    }

    public static boolean isDetailedSample(Sample sample) {
        return sample instanceof DetailedSample;
    }

    public static boolean isPlainSample(Sample sample) {
        return !isDetailedSample(sample);
    }

    private static boolean safeCategoryCheck(Sample sample, String category) {
        DetailedSample detailedSample = (DetailedSample) sample;
        if (detailedSample.getSampleClass() == null)
            return false;
        return category.equals(detailedSample.getSampleClass().getSampleCategory());
    }

    public static boolean isIdentitySample(Sample sample) {
        if (!isDetailedSample(sample))
            return false;
        return sample instanceof SampleIdentity || safeCategoryCheck(sample, SampleIdentity.CATEGORY_NAME);
    }

    public static boolean isTissueSample(Sample sample) {
        if (!isDetailedSample(sample))
            return false;
        return sample instanceof SampleTissue || safeCategoryCheck(sample, SampleTissue.CATEGORY_NAME);
    }

    public static boolean isTissueProcessingSample(Sample sample) {
        if (!isDetailedSample(sample))
            return false;
        return sample instanceof SampleTissueProcessing
                || safeCategoryCheck(sample, SampleTissueProcessing.CATEGORY_NAME);
    }

    public static boolean isLcmTubeSample(Sample sample) {
        if (!isDetailedSample(sample))
            return false;
        return sample instanceof SampleLCMTube;
    }

    public static boolean isStockSample(Sample sample) {
        return sample instanceof SampleStock || safeCategoryCheck(sample, SampleStock.CATEGORY_NAME);
    }

    public static boolean isAliquotSample(Sample sample) {
        return sample instanceof SampleAliquot || safeCategoryCheck(sample, SampleAliquot.CATEGORY_NAME);
    }

    public static boolean isDetailedLibrary(Library library) {
        return library instanceof DetailedLibrary;
    }

    public static boolean isIlluminaRun(Run run) {
        return run instanceof IlluminaRun;
    }

    public static boolean isPacBioRun(Run run) {
        return run instanceof PacBioRun;
    }

    public static boolean isLS454Run(Run run) {
        return run instanceof LS454Run;
    }

    public static boolean isSolidRun(Run run) {
        return run instanceof SolidRun;
    }

    public static boolean isOxfordNanoporeRun(Run run) {
        return run instanceof OxfordNanoporeRun;
    }

    public static boolean isOxfordNanoporeContainer(SequencerPartitionContainer container) {
        return container instanceof OxfordNanoporeContainer;
    }

    public static <T extends DetailedSample> T getParent(Class<T> targetParentClass, DetailedSample start) {
        for (DetailedSample current = deproxify(start.getParent()); current != null; current = deproxify(
                current.getParent())) {
            if (targetParentClass.isInstance(current)) {
                @SuppressWarnings("unchecked")
                T result = (T) current;
                return result;
            }
        }
        return null;
    }

    public static void validateNameOrThrow(Nameable object, NamingScheme namingScheme) throws IOException {
        ValidationResult val = namingScheme.validateName(object.getName());
        if (!val.isValid())
            throw new IOException("Save failed - invalid name:" + val.getMessage());
    }

    /**
     * universal temporary name prefix. TODO: these same methods are in sqlstore DbUtils;
     * use those when refactoring away the ProjectService.
     */
    static final private String TEMPORARY_NAME_PREFIX = "TEMPORARY_";

    /**
     * Generate a temporary name using a UUID.
     * 
     * @return Temporary name
     */
    static public String generateTemporaryName() {
        return TEMPORARY_NAME_PREFIX + UUID.randomUUID();
    }

    /**
     * Check if the nameable object has a temporary name.
     * 
     * @param nameable Nameable object
     * @return
     */
    static public boolean hasTemporaryName(Nameable nameable) {
        return nameable != null && nameable.getName() != null
                && nameable.getName().startsWith(TEMPORARY_NAME_PREFIX);
    }

    /**
     * Check if the Boxable item has a temporary name
     * 
     * @param boxable Boxable item
     * @return
     */
    static public boolean hasTemporaryAlias(Boxable boxable) {
        return boxable != null && boxable.getAlias() != null
                && boxable.getAlias().startsWith(TEMPORARY_NAME_PREFIX);
    }

    /**
     * Generates a unique barcode for a Nameable entity, and sets the identificationBarcode property for Boxables and LibraryDilutions.
     * 
     * @param nameable Nameable object
     * @throws IOException
     */
    public static void generateAndSetIdBarcode(Nameable nameable) throws IOException {
        String barcode = null;
        if (nameable instanceof LibraryDilution && nameable.getName() != null) {
            barcode = nameable.getName();
            if (((LibraryDilution) nameable).getLibrary() != null
                    && ((LibraryDilution) nameable).getLibrary().getAlias() != null) {
                barcode += "::" + ((LibraryDilution) nameable).getLibrary().getAlias();
            }
            ((LibraryDilution) nameable).setIdentificationBarcode(barcode);
        } else if (nameable instanceof Boxable && nameable.getName() != null) {
            barcode = nameable.getName();
            if (((Boxable) nameable).getAlias() != null) {
                barcode += "::" + ((Boxable) nameable).getAlias();
            }
            ((Boxable) nameable).setIdentificationBarcode(barcode);
        } else {
            throw new IOException("Error generating barcode");
        }
    }

    public static void appendSet(StringBuilder target, Collection<String> items, String prefix) {
        if (items.isEmpty())
            return;
        target.append(" ");
        target.append(prefix);
        target.append(": ");
        boolean first = true;
        for (String item : items) {
            if (first) {
                first = false;
            } else {
                target.append(", ");
            }
            target.append(item);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T deproxify(T from) {
        if (from instanceof HibernateProxy) {
            HibernateProxy proxy = (HibernateProxy) from;
            from = (T) proxy.getHibernateLazyInitializer().getImplementation();
        }
        return from;
    }

    public static String[] prefix(String prefix, String... suffixes) {
        String[] results = new String[suffixes.length];
        for (int i = 0; i < suffixes.length; i++) {
            results[i] = prefix + suffixes[i];
        }
        return results;
    }

    /**
     * Switches from a representation of date without time or a time zone to one that contains milliseconds from epoch as interpreted from
     * some place with a time zone. No good will come of this. Turn back now.
     * 
     * @param localDate A date without time.
     * @param timezone A time zone. We'll calculate milliseconds from the epoch from this particular time zone.
     * @return Milliseconds from the epoch.
     */
    public static Date toBadDate(LocalDate localDate, ZoneId timezone) {
        return localDate == null ? null : Date.from(localDate.atStartOfDay(timezone).toInstant());
    }

    public static Date toBadDate(LocalDate localDate) {
        return toBadDate(localDate, ZoneId.systemDefault());
    }

    public static Date toBadDate(LocalDateTime localDate) {
        return localDate == null ? null : toBadDate(localDate.toLocalDate());
    }

    public static <T> Predicate<T> rejectUntil(Predicate<T> check) {
        return new Predicate<T>() {
            private boolean state = false;

            @Override
            public boolean test(T t) {
                if (state) {
                    return true;
                }
                state = check.test(t);
                return false;
            }

        };
    }

    @SafeVarargs
    public static Set<String> concatSets(Set<String>... sets) {
        return Arrays.stream(sets).flatMap(Collection::stream).collect(Collectors.toSet());
    }
}