org.openmrs.module.kenyametadatatools.mflsync.MflSyncFromRemoteSpreadsheetTask.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.kenyametadatatools.mflsync.MflSyncFromRemoteSpreadsheetTask.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.kenyametadatatools.mflsync;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.openmrs.Location;
import org.openmrs.LocationAttribute;
import org.openmrs.LocationAttributeType;
import org.openmrs.api.context.Context;
import org.openmrs.module.kenyametadatatools.MetadataToolsUtils;
import org.openmrs.module.kenyametadatatools.task.TaskEngine;
import org.openmrs.util.OpenmrsUtil;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Date;
import java.util.Collections;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * Task to synchronize locations from a remote spreadsheet
 */
public class MflSyncFromRemoteSpreadsheetTask extends BaseMflSyncTask {

    protected URL spreadsheetUrl = null;

    /**
     * Creates task from spreadsheet URL
     * @param mflCodeAttrType the location attribute type for the MFL code
     * @param spreadsheetUrl the spreadsheet URL
     */
    public MflSyncFromRemoteSpreadsheetTask(LocationAttributeType mflCodeAttrType, URL spreadsheetUrl) {
        super(mflCodeAttrType);

        this.spreadsheetUrl = spreadsheetUrl;
    }

    /**
     * @see BaseMflSyncTask#doImport()
     */
    @Override
    public void doImport() throws Exception {

        File tmpZip = null;

        try {
            TaskEngine.log("Downloading MFL archive. This may take a few minutes ...");

            tmpZip = File.createTempFile("mfl", ".zip");

            OutputStream out = new BufferedOutputStream(new FileOutputStream(tmpZip));
            OpenmrsUtil.copyFile(spreadsheetUrl.openStream(), out);

            TaskEngine.log("Downloaded archive " + tmpZip.getName());
            TaskEngine.log("Looking for XLS files in archive ...");

            ZipFile zipFile = new ZipFile(tmpZip);
            for (ZipEntry entry : Collections.list(zipFile.entries())) {
                if (entry.getName().toLowerCase().endsWith(".xls")) {
                    TaskEngine.log("Importing '" + entry.getName() + "' ...");
                    importXls(zipFile.getInputStream(entry));
                }
            }
        } finally {
            if (tmpZip != null) {
                tmpZip.delete();
            }
        }
    }

    /**
     * Imports a MFL spreadsheet from a stream
     * @param stream the input stream
     * @throws IOException if an error occurred
     */
    protected void importXls(InputStream stream) throws IOException {
        POIFSFileSystem poifs = new POIFSFileSystem(stream);
        HSSFWorkbook wbook = new HSSFWorkbook(poifs);
        HSSFSheet sheet = wbook.getSheetAt(0);

        for (int r = sheet.getFirstRowNum() + 1; r <= sheet.getLastRowNum(); ++r) {
            HSSFRow row = sheet.getRow(r);
            String code = String.valueOf(((Double) cellValue(row.getCell(0))).intValue());
            String name = (String) cellValue(row.getCell(1));
            String province = (String) cellValue(row.getCell(2));
            String type = (String) cellValue(row.getCell(6));

            if (StringUtils.isEmpty(name)) {
                TaskEngine.logError("Unable to import location " + code + " with empty name");
            } else if (StringUtils.isEmpty(code)) {
                TaskEngine.logError("Unable to import location '" + name + "' with invalid code");
            } else {
                importLocation(code, name.trim(), province, type);
            }
        }
    }

    /**
     * Imports a location
     * @param code the MFL code
     * @param name the location name
     * @param province the province
     * @param type location type
     */
    protected void importLocation(String code, String name, String province, String type) {
        // Map MFL fields to location properties
        String locationName = name;
        String locationDescription = type;
        String locationStateProvince = province;
        String locationCountry = "Kenya";

        // Look for existing location with this code
        Location location = lookupMflCodeCache(code);

        boolean doCreate = false, doUpdate = false;

        // Create new location if it doesn't exist
        if (location == null) {
            location = new Location();
            location.setCreator(Context.getAuthenticatedUser());
            location.setDateCreated(new Date());

            // Create MFL code attribute for new location
            LocationAttribute mfcAttr = new LocationAttribute();
            mfcAttr.setAttributeType(getMflCodeAttributeType());
            mfcAttr.setValue(code);
            mfcAttr.setOwner(location);
            location.addAttribute(mfcAttr);

            doCreate = true;
        } else {
            // Un-retire location if necessary
            if (location.getRetired()) {
                location.setRetired(false);
                location.setRetiredBy(null);
                location.setRetireReason(null);
                doUpdate = true;
            } else {
                // Compute hashes of existing location fields and incoming fields
                String incomingHash = MetadataToolsUtils.hash(locationName, locationDescription,
                        locationStateProvince, locationCountry);
                String existingHash = MetadataToolsUtils.hash(location.getName(), location.getDescription(),
                        location.getStateProvince(), location.getCountry());

                // Only update if hashes are different
                if (!incomingHash.equals(existingHash)) {
                    doUpdate = true;
                }
            }
        }

        if (doCreate) {
            TaskEngine.log("Creating new location '" + locationName + "' with code " + code);
            createdCount++;
        } else if (doUpdate) {
            TaskEngine.log("Updating existing location '" + locationName + "' with code " + code);
            updatedCount++;
        }

        if (doCreate || doUpdate) {
            location.setName(locationName);
            location.setDescription(locationDescription);
            location.setStateProvince(locationStateProvince);
            location.setCountry(locationCountry);

            Context.getLocationService().saveLocation(location);
            updateMflCodeCache(code, location);
        }

        markLocationSynced(location);

        Context.flushSession();
        Context.clearSession();
    }

    /**
     * Extracts the value of the given cell
     * @param cell the cell
     * @return the cell value
     */
    private Object cellValue(HSSFCell cell) {
        return cell.getCellType() == 0 ? cell.getNumericCellValue() : cell.getStringCellValue();
    }
}