org.openmrs.module.clinicalsummary.io.UploadSummariesTask.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.clinicalsummary.io.UploadSummariesTask.java

Source

/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.clinicalsummary.io;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.module.clinicalsummary.enumeration.TaskStatus;
import org.openmrs.module.clinicalsummary.io.utils.TaskConstants;
import org.openmrs.module.clinicalsummary.io.utils.TaskUtils;
import org.springframework.util.FileCopyUtils;

/**
 *
 */
class UploadSummariesTask extends SummariesTask {

    private static final int IV_SIZE = 16;

    private static final Log log = LogFactory.getLog(UploadSummariesTask.class);

    private byte[] initVector;

    public UploadSummariesTask(final String password, final String filename) {
        super(password, filename);
    }

    /**
     * In order to correctly perform the encryption - decryption process, user must store their init vector table. This init vector will be given to the
     * user as a small file and it is required to perform the decryption process.
     *
     * @throws Exception
     */
    protected void processInitVector() throws Exception {
        String encryptedFilename = StringUtils.join(Arrays.asList(filename, TaskConstants.FILE_TYPE_ENCRYPTED),
                ".");
        ZipFile encryptedFile = new ZipFile(new File(TaskUtils.getEncryptedOutputPath(), encryptedFilename));

        Enumeration<? extends ZipEntry> entries = encryptedFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = entries.nextElement();
            if (zipEntry.getName().endsWith(TaskConstants.FILE_TYPE_SECRET)) {
                InputStream inputStream = encryptedFile.getInputStream(zipEntry);
                initVector = FileCopyUtils.copyToByteArray(inputStream);
                if (initVector.length != IV_SIZE) {
                    throw new Exception("Secret file is corrupted or invalid secret file are being used.");
                }
            }
        }
    }

    /**
     * Method to initialize the cipher object with the correct encryption algorithm.
     *
     * @throws Exception
     */
    protected void initializeCipher() throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance(TaskConstants.SECRET_KEY_FACTORY);
        KeySpec spec = new PBEKeySpec(password.toCharArray(), password.getBytes(), 1024, 128);
        SecretKey tmp = factory.generateSecret(spec);

        if (log.isDebugEnabled())
            log.debug("Secret Key Length: " + tmp.getEncoded().length);

        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), TaskConstants.KEY_SPEC);

        cipher = Cipher.getInstance(TaskConstants.CIPHER_CONFIGURATION);
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initVector));
    }

    /**
     * Method that will be called to process the summary collection file. The upload process will unpack the zipped collection of summary files and then
     * decrypt them.
     *
     * @throws Exception
     */
    protected void processSummaries() throws Exception {
        String zipFilename = StringUtils.join(Arrays.asList(filename, TaskConstants.FILE_TYPE_ZIP), ".");
        String encryptedFilename = StringUtils.join(Arrays.asList(filename, TaskConstants.FILE_TYPE_ENCRYPTED),
                ".");

        File file = new File(TaskUtils.getZippedOutputPath(), zipFilename);
        OutputStream outStream = new BufferedOutputStream(new FileOutputStream(file));
        ZipFile encryptedFile = new ZipFile(new File(TaskUtils.getEncryptedOutputPath(), encryptedFilename));

        Enumeration<? extends ZipEntry> entries = encryptedFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = entries.nextElement();
            String zipEntryName = zipEntry.getName();
            if (!zipEntryName.endsWith(TaskConstants.FILE_TYPE_SAMPLE)
                    && !zipEntryName.endsWith(TaskConstants.FILE_TYPE_SECRET)) {
                int count;
                byte[] data = new byte[TaskConstants.BUFFER_SIZE];
                CipherInputStream zipCipherInputStream = new CipherInputStream(
                        encryptedFile.getInputStream(zipEntry), cipher);
                while ((count = zipCipherInputStream.read(data, 0, TaskConstants.BUFFER_SIZE)) != -1) {
                    outStream.write(data, 0, count);
                }
                zipCipherInputStream.close();
            }
        }
        outStream.close();

        File outputPath = TaskUtils.getSummaryOutputPath();
        ZipFile zipFile = new ZipFile(file);
        Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
        while (zipEntries.hasMoreElements()) {
            ZipEntry zipEntry = zipEntries.nextElement();
            processedFilename = zipEntry.getName();
            File f = new File(outputPath, zipEntry.getName());
            // ensure that the parent path exists
            File parent = f.getParentFile();
            if (parent.exists() || parent.mkdirs()) {
                FileCopyUtils.copy(zipFile.getInputStream(zipEntry),
                        new BufferedOutputStream(new FileOutputStream(f)));
            }
        }
    }

    /**
     * Method that will be called to process the index file. Index file contains sql statement for the summary sheet index table in the database. The
     * upload process will execute mysql to load back into the database. To execute mysql correctly, the database user must have RELOAD privilege
     *
     * @throws Exception
     */
    protected void processIndex() throws Exception {
        File indexFile = new File(TaskUtils.getSummaryOutputPath(), TaskConstants.INDEX_CONFIGURATION_SQL_FILE);

        String path = indexFile.getAbsolutePath();
        path = path.replace("\\", "/");

        String[] commands = { "mysql", "-e", "source " + path, "-f", "-u" + databaseUser, "-p" + databasePassword,
                "-h" + databaseHost, "-P" + databasePort, "-D" + databaseName };

        TaskUtils.executeCommand(TaskUtils.getSummaryOutputPath(), commands);
    }

    /**
     * @see SummariesTask#process()
     */
    @Override
    protected void process() throws Exception {
        setStatus(TaskStatus.TASK_RUNNING_UPLOAD);
        prepareDatabaseProperties();
        processInitVector();
        initializeCipher();
        processSummaries();
        processIndex();
    }
}