ch.systemsx.cisd.openbis.plugin.generic.client.web.server.parser.SampleUploadSectionsParser.java Source code

Java tutorial

Introduction

Here is the source code for ch.systemsx.cisd.openbis.plugin.generic.client.web.server.parser.SampleUploadSectionsParser.java

Source

/*
 * Copyright 2009 ETH Zuerich, CISD
 *
 * 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 ch.systemsx.cisd.openbis.plugin.generic.client.web.server.parser;

import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;

import ch.systemsx.cisd.common.exceptions.UserFailureException;
import ch.systemsx.cisd.common.io.DelegatedReader;
import ch.systemsx.cisd.common.parser.IParserObjectFactory;
import ch.systemsx.cisd.common.parser.IParserObjectFactoryFactory;
import ch.systemsx.cisd.common.parser.IPropertyMapper;
import ch.systemsx.cisd.common.parser.ParserException;
import ch.systemsx.cisd.common.spring.IUncheckedMultipartFile;
import ch.systemsx.cisd.openbis.generic.client.web.client.dto.BatchRegistrationResult;
import ch.systemsx.cisd.openbis.generic.client.web.server.BisTabFileLoader;
import ch.systemsx.cisd.openbis.generic.client.web.server.UploadedFilesBean;
import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSamplesWithTypes;
import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;

/**
 * Helps uploading samples of multiple types from one file. Parses the file.
 * 
 * @author Izabela Adamczyk
 * @author Tomasz Pylak
 */
public class SampleUploadSectionsParser {
    public static class BatchSamplesRegistration {
        private final List<NewSamplesWithTypes> samples;

        private final List<BatchRegistrationResult> resultList;

        private final String[] sampleCodes;

        public BatchSamplesRegistration(List<NewSamplesWithTypes> samples, List<BatchRegistrationResult> resultList,
                String[] sampleCodes) {
            this.samples = samples;
            this.resultList = resultList;
            this.sampleCodes = sampleCodes;
        }

        public List<NewSamplesWithTypes> getSamples() {
            return samples;
        }

        public List<BatchRegistrationResult> getResultList() {
            return resultList;
        }

        public String[] getCodes() {
            return sampleCodes;
        }
    }

    public interface SampleCodeGenerator {
        /** generates 'size' codes for new samples */
        List<String> generateCodes(int size);
    }

    public static BatchSamplesRegistration prepareSamples(final SampleType sampleType,
            final UploadedFilesBean uploadedFiles, String defaultGroupIdentifier,
            final SampleCodeGenerator sampleCodeGeneratorOrNull, final boolean allowExperiments) {
        final List<NewSamplesWithTypes> newSamples = new ArrayList<NewSamplesWithTypes>();
        boolean isAutoGenerateCodes = (sampleCodeGeneratorOrNull != null);
        final List<BatchRegistrationResult> results = loadSamplesFromFiles(uploadedFiles, sampleType,
                isAutoGenerateCodes, newSamples, allowExperiments);
        generateIdentifiersIfNecessary(defaultGroupIdentifier, sampleCodeGeneratorOrNull, isAutoGenerateCodes,
                newSamples);
        return new BatchSamplesRegistration(newSamples, results, parseCodes(newSamples));
    }

    private static String[] parseCodes(final List<NewSamplesWithTypes> newSamples) {
        List<String> codes = new ArrayList<String>();
        for (NewSamplesWithTypes st : newSamples) {
            for (NewSample s : st.getNewSamples()) {
                codes.add(SampleIdentifierFactory.parse(s.getIdentifier()).getSampleCode());
            }
        }
        return codes.toArray(new String[0]);
    }

    private static BisTabFileLoader<NewSample> createSampleLoader(final SampleType sampleType,
            final boolean isAutoGenerateCodes, final boolean allowExperiments) {
        final BisTabFileLoader<NewSample> tabFileLoader = new BisTabFileLoader<NewSample>(
                new IParserObjectFactoryFactory<NewSample>() {
                    public final IParserObjectFactory<NewSample> createFactory(final IPropertyMapper propertyMapper)
                            throws ParserException {
                        return new NewSampleParserObjectFactory(sampleType, propertyMapper,
                                isAutoGenerateCodes == false, allowExperiments);
                    }
                }, true);
        return tabFileLoader;
    }

    static class FileSection {
        private final String content;

        private final String sectionName;

        public FileSection(String content, String sectionName) {
            this.sectionName = sectionName;
            this.content = content;
        }

        public String getContent() {
            return content;
        }

        public String getSectionName() {
            return sectionName;
        }
    }

    private static List<FileSection> extractSections(IUncheckedMultipartFile multipartFile) {
        List<FileSection> sections = new ArrayList<FileSection>();
        InputStreamReader reader = new InputStreamReader(multipartFile.getInputStream());
        try {
            LineIterator it = IOUtils.lineIterator(reader);
            StringBuilder sb = null;
            String sectionName = null;
            while (it.hasNext()) {
                String line = it.nextLine();
                String newSectionName = tryGetSectionName(line);
                if (newSectionName != null) {
                    if (sectionName != null && sb != null) {
                        sections.add(new FileSection(sb.toString(), sectionName));
                    }
                    sectionName = newSectionName;
                    sb = new StringBuilder();
                } else if (sectionName == null || sb == null) {
                    throw new UserFailureException("Discovered the unnamed section in the file");
                } else {
                    if (sb.length() != 0) {
                        sb.append("\n");
                    }
                    sb.append(line);
                }
                if (it.hasNext() == false) {
                    sections.add(new FileSection(sb.toString(), sectionName));
                }
            }
        } finally {
            IOUtils.closeQuietly(reader);
        }
        return sections;
    }

    private static String tryGetSectionName(String line) {
        final String beginSection = "[";
        final String endSection = "]";
        if (line == null) {
            return null;
        }
        String trimmedLine = line.trim();
        if (trimmedLine.startsWith(beginSection) && trimmedLine.endsWith(endSection)) {
            return trimmedLine.substring(1, trimmedLine.length() - 1);
        } else {
            return null;
        }
    }

    private static List<BatchRegistrationResult> loadSamplesFromFiles(UploadedFilesBean uploadedFiles,
            SampleType sampleType, boolean isAutoGenerateCodes, final List<NewSamplesWithTypes> newSamples,
            boolean allowExperiments) {

        final List<BatchRegistrationResult> results = new ArrayList<BatchRegistrationResult>(uploadedFiles.size());

        for (final IUncheckedMultipartFile multipartFile : uploadedFiles.iterable()) {
            List<FileSection> sampleSections = new ArrayList<FileSection>();
            if (sampleType.isDefinedInFileSampleTypeCode()) {
                sampleSections.addAll(extractSections(multipartFile));
            } else {
                sampleSections.add(new FileSection(new String(multipartFile.getBytes()), sampleType.getCode()));
            }
            int sampleCounter = 0;
            for (FileSection fs : sampleSections) {
                final StringReader stringReader = new StringReader(fs.getContent());
                SampleType typeFromSection = new SampleType();
                typeFromSection.setCode(fs.getSectionName());
                final BisTabFileLoader<NewSample> tabFileLoader = createSampleLoader(typeFromSection,
                        isAutoGenerateCodes, allowExperiments);
                String sectionInFile = sampleSections.size() == 1 ? "" : " (section:" + fs.getSectionName() + ")";
                final List<NewSample> loadedSamples = tabFileLoader.load(
                        new DelegatedReader(stringReader, multipartFile.getOriginalFilename() + sectionInFile));
                if (loadedSamples.size() > 0) {
                    newSamples.add(new NewSamplesWithTypes(typeFromSection, loadedSamples));
                    sampleCounter += loadedSamples.size();
                }
            }
            results.add(new BatchRegistrationResult(multipartFile.getOriginalFilename(),
                    String.format("%d sample(s) found and registered.", sampleCounter)));
        }
        return results;
    }

    private static void generateIdentifiersIfNecessary(String defaultGroupIdentifier,
            SampleCodeGenerator sampleCodeGeneratorOrNull, boolean isAutoGenerateCodes,
            List<NewSamplesWithTypes> newSamples) {
        if (sampleCodeGeneratorOrNull != null) {
            for (NewSamplesWithTypes st : newSamples) {
                generateIdentifiers(defaultGroupIdentifier, sampleCodeGeneratorOrNull, st.getNewSamples());
            }
        }
    }

    private static void generateIdentifiers(String defaultGroupIdentifier,
            final SampleCodeGenerator sampleCodeGenerator, final List<NewSample> newSamples) {
        List<String> codes = sampleCodeGenerator.generateCodes(newSamples.size());
        for (int i = 0; i < newSamples.size(); i++) {
            newSamples.get(i).setIdentifier(defaultGroupIdentifier + "/" + codes.get(i));
        }
    }

}