ubic.gemma.core.analysis.report.ArrayDesignReportServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for ubic.gemma.core.analysis.report.ArrayDesignReportServiceImpl.java

Source

/*
 * The Gemma project.
 *
 * Copyright (c) 2006 University of British Columbia
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package ubic.gemma.core.analysis.report;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;
import ubic.basecode.util.FileTools;
import ubic.gemma.model.common.Auditable;
import ubic.gemma.model.common.auditAndSecurity.AuditEvent;
import ubic.gemma.model.common.auditAndSecurity.eventType.*;
import ubic.gemma.model.expression.arrayDesign.ArrayDesign;
import ubic.gemma.model.expression.arrayDesign.ArrayDesignValueObject;
import ubic.gemma.persistence.service.common.auditAndSecurity.AuditEventService;
import ubic.gemma.persistence.service.expression.arrayDesign.ArrayDesignService;
import ubic.gemma.persistence.util.EntityUtils;
import ubic.gemma.persistence.util.Settings;

import java.io.*;
import java.util.*;

/**
 * @author jsantos
 */
@Component
public class ArrayDesignReportServiceImpl implements ArrayDesignReportService {
    private final static String HOME_DIR = Settings.getString("gemma.appdata.home");
    private final static Log log = LogFactory.getLog(ArrayDesignReportServiceImpl.class);
    private final static String ARRAY_DESIGN_REPORT_DIR = "ArrayDesignReports";
    private final static String ARRAY_DESIGN_REPORT_FILE_NAME_PREFIX = "ArrayDesignReport";
    // For all array designs
    private final static String ARRAY_DESIGN_SUMMARY = "AllArrayDesignsSummary";

    @Autowired
    private ArrayDesignService arrayDesignService;

    @Autowired
    private AuditEventService auditEventService;

    /**
     * Batch of classes we can get events for all at once.
     */
    @SuppressWarnings("unchecked")
    private final Class<? extends AuditEventType>[] eventTypes = new Class[] { ArrayDesignSequenceUpdateEvent.class,
            ArrayDesignSequenceAnalysisEvent.class, ArrayDesignGeneMappingEvent.class,
            ArrayDesignRepeatAnalysisEvent.class };

    @Override
    public void generateAllArrayDesignReport() {
        ArrayDesignReportServiceImpl.log.info("Generating report summarizing all platforms ... ");

        // obtain time information (for timestamp)
        Date d = new Date(System.currentTimeMillis());
        String timestamp = DateFormatUtils.format(d, "yyyy.MM.dd HH:mm");

        long numCsBioSequences = arrayDesignService.numAllCompositeSequenceWithBioSequences();
        long numCsBlatResults = arrayDesignService.numAllCompositeSequenceWithBlatResults();
        long numCsGenes = arrayDesignService.numAllCompositeSequenceWithGenes();
        long numGenes = arrayDesignService.numAllGenes();

        // create a surrogate ArrayDesignValue object to represent the total of all platforms
        ArrayDesignValueObject adVo = new ArrayDesignValueObject(-1L);
        adVo.setNumProbeSequences(Long.toString(numCsBioSequences));
        adVo.setNumProbeAlignments(Long.toString(numCsBlatResults));
        adVo.setNumProbesToGenes(Long.toString(numCsGenes));
        adVo.setNumGenes(Long.toString(numGenes));
        adVo.setDateCached(timestamp);
        // remove file first
        File f = new File(ArrayDesignReportServiceImpl.HOME_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_SUMMARY);
        if (f.exists()) {
            if (!f.canWrite() || !f.delete()) {
                ArrayDesignReportServiceImpl.log.warn("Cannot write to file.");
                return;
            }
        }
        try (FileOutputStream fos = new FileOutputStream(ArrayDesignReportServiceImpl.HOME_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_SUMMARY);
                ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(adVo);
        } catch (Throwable e) {
            // cannot write to file. Just fail gracefully.
            ArrayDesignReportServiceImpl.log.error("Cannot write to file.");
        }
        ArrayDesignReportServiceImpl.log.info("Done making reports");
    }

    @Override
    @Secured({ "GROUP_AGENT" })
    public void generateArrayDesignReport() {
        this.initDirectories();

        Collection<ArrayDesignValueObject> ads = arrayDesignService.loadAllValueObjects();
        ArrayDesignReportServiceImpl.log.info("Creating reports for " + ads.size() + " platforms");
        for (ArrayDesignValueObject ad : ads) {
            this.generateArrayDesignReport(ad);
        }

        ArrayDesignReportServiceImpl.log.info("Generating global report");
        this.generateAllArrayDesignReport();
    }

    @Override
    public void generateArrayDesignReport(ArrayDesignValueObject adVo) {

        ArrayDesign ad = arrayDesignService.load(adVo.getId());
        if (ad == null)
            return;

        // obtain time information (for timestamp)
        Date d = new Date(System.currentTimeMillis());
        String timestamp = DateFormatUtils.format(d, "yyyy.MM.dd HH:mm");

        long numProbes = arrayDesignService.getCompositeSequenceCount(ad);
        long numCsBioSequences = arrayDesignService.numCompositeSequenceWithBioSequences(ad);
        long numCsBlatResults = arrayDesignService.numCompositeSequenceWithBlatResults(ad);
        long numCsGenes = arrayDesignService.numCompositeSequenceWithGenes(ad);
        long numGenes = arrayDesignService.numGenes(ad);

        adVo.setDesignElementCount((int) numProbes);
        adVo.setNumProbeSequences(Long.toString(numCsBioSequences));
        adVo.setNumProbeAlignments(Long.toString(numCsBlatResults));
        adVo.setNumProbesToGenes(Long.toString(numCsGenes));
        adVo.setNumGenes(Long.toString(numGenes));
        adVo.setDateCached(timestamp);

        // check the directory exists.
        String reportDir = ArrayDesignReportServiceImpl.HOME_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_DIR;
        File reportDirF = new File(reportDir);
        if (!reportDirF.exists()) {
            EntityUtils.mkdirs(reportDirF);
        }

        String reportFileName = reportDir + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_FILE_NAME_PREFIX + "." + adVo.getId();
        File f = new File(reportFileName);

        if (f.exists()) {
            if (!f.canWrite() || !f.delete()) {
                ArrayDesignReportServiceImpl.log.error(
                        "Report exists but cannot overwrite, leaving the old one in place: " + reportFileName);
                return;
            }
        }

        try (FileOutputStream fos = new FileOutputStream(reportFileName);
                ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(adVo);
        } catch (Throwable e) {
            ArrayDesignReportServiceImpl.log.error("Cannot write to file: " + reportFileName);
            return;
        }
        ArrayDesignReportServiceImpl.log.info("Generated report for " + ad);
    }

    @Override
    public ArrayDesignValueObject generateArrayDesignReport(Long id) {
        Collection<ArrayDesignValueObject> adVo = arrayDesignService
                .loadValueObjectsByIds(Collections.singleton(id));
        if (adVo != null && adVo.size() > 0) {
            this.generateArrayDesignReport(adVo.iterator().next());
            return this.getSummaryObject(id);
        }
        ArrayDesignReportServiceImpl.log.warn("No value objects return for requested platforms");
        return null;
    }

    /**
     * Get a specific cached summary object
     *
     * @return arrayDesignValueObject the specified summary object
     */
    @Override
    public ArrayDesignValueObject getSummaryObject(Long id) {
        ArrayDesignValueObject adVo = null;
        File f = new File(ArrayDesignReportServiceImpl.HOME_DIR + "/"
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_FILE_NAME_PREFIX + "." + id);
        if (f.exists()) {
            try (FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis)) {

                adVo = (ArrayDesignValueObject) ois.readObject();

            } catch (Throwable e) {
                return null;
            }
        }
        return adVo;
    }

    /**
     * Get the cached summary object that represents all platforms.
     *
     * @return arrayDesignValueObject the summary object that represents the grand total of all array designs
     */
    @Override
    public ArrayDesignValueObject getSummaryObject() {
        ArrayDesignValueObject adVo = null;
        File f = new File(ArrayDesignReportServiceImpl.HOME_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_DIR + File.separatorChar
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_SUMMARY);
        if (f.exists()) {
            try (FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis)) {
                adVo = (ArrayDesignValueObject) ois.readObject();
            } catch (Throwable e) {
                return null;
            }
        }
        return adVo;
    }

    /**
     * Get the cached summary objects
     *
     * @return arrayDesignValueObjects the specified summary object
     */
    @Override
    public Collection<ArrayDesignValueObject> getSummaryObject(Collection<Long> ids) {
        Collection<ArrayDesignValueObject> adVos = new ArrayList<>();
        for (Long id : ids) {
            ArrayDesignValueObject adVo = this.getSummaryObject(id);
            if (adVo != null) {
                adVos.add(this.getSummaryObject(id));
            }
        }
        return adVos;
    }

    /**
     * Fill in event information
     */
    @Override
    public void fillEventInformation(Collection<ArrayDesignValueObject> adVos) {

        if (adVos == null || adVos.size() == 0)
            return;

        StopWatch watch = new StopWatch();
        watch.start();

        Collection<Long> ids = new ArrayList<>();
        for (Object object : adVos) {
            ArrayDesignValueObject adVo = (ArrayDesignValueObject) object;
            Long id = adVo.getId();
            if (id == null)
                continue;
            ids.add(id);
        }

        if (ids.size() == 0)
            return;

        Collection<Class<? extends AuditEventType>> typesToGet = Arrays.asList(eventTypes);

        Collection<ArrayDesign> arrayDesigns = arrayDesignService.load(ids);

        Map<Long, ArrayDesign> idMap = EntityUtils.getIdMap(arrayDesigns);

        Map<Class<? extends AuditEventType>, Map<Auditable, AuditEvent>> events = auditEventService
                .getLastEvents(arrayDesigns, typesToGet);

        Map<Auditable, AuditEvent> geneMappingEvents = events.get(ArrayDesignGeneMappingEvent.class);
        Map<Auditable, AuditEvent> sequenceUpdateEvents = events.get(ArrayDesignSequenceUpdateEvent.class);
        Map<Auditable, AuditEvent> sequenceAnalysisEvents = events.get(ArrayDesignSequenceAnalysisEvent.class);
        Map<Auditable, AuditEvent> repeatAnalysisEvents = events.get(ArrayDesignRepeatAnalysisEvent.class);

        for (ArrayDesignValueObject adVo : adVos) {

            Long id = adVo.getId();
            ArrayDesign ad = idMap.get(id);

            if (geneMappingEvents.containsKey(ad)) {
                AuditEvent event = geneMappingEvents.get(ad);
                if (event != null) {
                    adVo.setLastGeneMapping(event.getDate());
                }
            }

            if (sequenceUpdateEvents.containsKey(ad)) {
                AuditEvent event = sequenceUpdateEvents.get(ad);
                if (event != null) {
                    adVo.setLastSequenceUpdate(event.getDate());
                }
            }

            if (sequenceAnalysisEvents.containsKey(ad)) {
                AuditEvent event = sequenceAnalysisEvents.get(ad);
                if (event != null) {
                    adVo.setLastSequenceAnalysis(event.getDate());
                }
            }
            if (repeatAnalysisEvents.containsKey(ad)) {
                AuditEvent event = repeatAnalysisEvents.get(ad);
                if (event != null) {
                    adVo.setLastRepeatMask(event.getDate());
                }
            }

        }

        watch.stop();
        if (watch.getTime() > 1000)
            ArrayDesignReportServiceImpl.log.info("Added event information in " + watch.getTime() + "ms");

    }

    @Override
    public void fillInSubsumptionInfo(Collection<ArrayDesignValueObject> valueObjects) {
        Collection<Long> ids = new ArrayList<>();
        for (Object object : valueObjects) {
            if (object == null)
                continue;
            ArrayDesignValueObject adVo = (ArrayDesignValueObject) object;
            ids.add(adVo.getId());
        }
        Map<Long, Boolean> isSubsumed = arrayDesignService.isSubsumed(ids);
        Map<Long, Boolean> hasSubsumees = arrayDesignService.isSubsumer(ids);
        Map<Long, Boolean> isMergee = arrayDesignService.isMergee(ids);
        Map<Long, Boolean> isMerged = arrayDesignService.isMerged(ids);

        for (ArrayDesignValueObject adVo : valueObjects) {
            Long id = adVo.getId();
            if (isSubsumed.containsKey(id)) {
                adVo.setIsSubsumed(isSubsumed.get(id));
            }
            if (hasSubsumees.containsKey(id)) {
                adVo.setIsSubsumer(hasSubsumees.get(id));
            }
            if (isMergee.containsKey(id)) {
                adVo.setIsMergee(isMergee.get(id));
            }
            if (isMerged.containsKey(id)) {
                adVo.setIsMerged(isMerged.get(id));
            }
        }

    }

    /**
     * Fill in the probe summary statistics
     */
    @Override
    public void fillInValueObjects(Collection<ArrayDesignValueObject> adVos) {
        for (ArrayDesignValueObject origVo : adVos) {
            if (origVo == null)
                continue;
            ArrayDesignValueObject cachedVo = this.getSummaryObject(origVo.getId());
            if (cachedVo != null) {
                origVo.setNumProbeSequences(cachedVo.getNumProbeSequences());
                origVo.setNumProbeAlignments(cachedVo.getNumProbeAlignments());
                origVo.setNumProbesToGenes(cachedVo.getNumProbesToGenes());
                origVo.setNumGenes(cachedVo.getNumGenes());
                origVo.setDateCached(cachedVo.getDateCached());
                origVo.setDesignElementCount(cachedVo.getDesignElementCount());
            }
        }
    }

    @Override
    public String getLastSequenceUpdateEvent(Long id) {
        return this.getLastEvent(id, ArrayDesignSequenceUpdateEvent.class);
    }

    @Override
    public String getLastSequenceAnalysisEvent(Long id) {
        return this.getLastEvent(id, ArrayDesignSequenceAnalysisEvent.class);
    }

    @Override
    public String getLastRepeatMaskEvent(Long id) {
        return this.getLastEvent(id, ArrayDesignRepeatAnalysisEvent.class);
    }

    @Override
    public String getLastGeneMappingEvent(Long id) {
        return this.getLastEvent(id, ArrayDesignGeneMappingEvent.class);

    }

    private String getLastEvent(Long id, Class<? extends AuditEventType> eventType) {
        ArrayDesign ad = arrayDesignService.load(id);

        if (ad == null)
            return "";

        List<AuditEvent> events2 = auditEventService.getEvents(ad);

        String analysisEventString;
        List<AuditEvent> events = new ArrayList<>();

        for (AuditEvent event : events2) {
            if (event == null)
                continue; // legacy of ordered-list which could end up with gaps; should not be needed
            // any more
            if (event.getEventType() != null && eventType.isAssignableFrom(event.getEventType().getClass())) {
                events.add(event);
            }
        }

        if (events.size() == 0) {
            return "[None]";
        }

        // add the most recent events to the report. There should always be at least one creation event.
        AuditEvent lastEvent = events.get(events.size() - 1);
        analysisEventString = DateFormatUtils.format(lastEvent.getDate(), "yyyy.MMM.dd hh:mm aa");

        return analysisEventString;
    }

    private void initDirectories() {
        FileTools.createDir(ArrayDesignReportServiceImpl.HOME_DIR);
        FileTools.createDir(ArrayDesignReportServiceImpl.HOME_DIR + File.separator
                + ArrayDesignReportServiceImpl.ARRAY_DESIGN_REPORT_DIR);
    }

}