at.medevit.ch.artikelstamm.elexis.common.ui.provider.atccache.ATCCodeCache.java Source code

Java tutorial

Introduction

Here is the source code for at.medevit.ch.artikelstamm.elexis.common.ui.provider.atccache.ATCCodeCache.java

Source

/*******************************************************************************
 * Copyright (c) 2014 MEDEVIT.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     MEDEVIT <office@medevit.at> - initial API and implementation
 ******************************************************************************/
package at.medevit.ch.artikelstamm.elexis.common.ui.provider.atccache;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.medevit.atc_codes.ATCCode;
import at.medevit.atc_codes.ATCCodeService;
import at.medevit.ch.artikelstamm.elexis.common.internal.ATCCodeServiceConsumer;
import ch.artikelstamm.elexis.common.ArtikelstammItem;
import ch.elexis.core.ui.UiDesk;
import ch.elexis.data.NamedBlob2;
import ch.elexis.data.PersistentObject;
import ch.rgw.tools.JdbcLink.Stm;
import ch.rgw.tools.TimeTool;

/**
 * Provide a cache for the number of elements available in the Artikelstamm set for each ATC code.
 * 
 */
public class ATCCodeCache {

    private static ATCCodeService atcCodeService = ATCCodeServiceConsumer.getATCCodeService();
    private static HashMap<String, Integer> cache;

    private static Logger log = LoggerFactory.getLogger(ATCCodeCache.class);
    private static final String NAMED_BLOB_PREFIX = "ATC_ARTSTAMM_CACHE";

    private static void initCache() throws IOException, ClassNotFoundException {
        deserializeFromDatabase(determineBlobId());
    }

    private static String determineBlobId() {
        return NAMED_BLOB_PREFIX + "_" + ArtikelstammItem.getCurrentVersion();
    }

    @SuppressWarnings("unchecked")
    private static void deserializeFromDatabase(String id) throws IOException, ClassNotFoundException {

        NamedBlob2 cacheStorage = NamedBlob2.load(id);
        if (cacheStorage != null) {
            ByteArrayInputStream ba = new ByteArrayInputStream(cacheStorage.getBytes());
            ObjectInputStream oba = new ObjectInputStream(ba);
            cache = (HashMap<String, Integer>) oba.readObject();
            oba.close();
            ba.close();

        } else {
            ProgressMonitorDialog pmd = new ProgressMonitorDialog(UiDesk.getTopShell());
            try {
                pmd.run(false, false, new IRunnableWithProgress() {

                    @Override
                    public void run(IProgressMonitor monitor)
                            throws InvocationTargetException, InterruptedException {
                        rebuildCache(monitor);
                    }
                });
            } catch (InvocationTargetException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 
     * @param element
     * @return the number of elements found, or -1 in case of any error
     */
    public static int getAvailableArticlesByATCCode(ATCCode element) {
        if (cache == null) {
            try {
                initCache();
            } catch (IOException | ClassNotFoundException e) {
                log.error("Error initializing cache", e);
                cache = null;
                return -1;
            }
        }

        Integer value = cache.get(element.atcCode);
        return (value != null) ? value : 0;
    }

    public static void rebuildCache(IProgressMonitor monitor) {
        if (atcCodeService == null) {
            return;
        }
        List<ATCCode> allATCCodes = atcCodeService.getAllATCCodes();
        int numberOfATCCodes = allATCCodes.size();

        monitor.beginTask("Rebuilding index of available articles per ATC Code", numberOfATCCodes + 1);

        cache = new HashMap<String, Integer>(numberOfATCCodes);

        TreeMap<String, Integer> tm = new TreeMap<String, Integer>();
        String query = "SELECT DISTINCT(" + ArtikelstammItem.FLD_ATC + ") FROM " + ArtikelstammItem.TABLENAME;
        log.debug("ArtikelstammImporter {} numberOfATCCodes using query {}:", numberOfATCCodes, query);
        Stm stm = PersistentObject.getConnection().getStatement();
        ResultSet rs = stm.query(query);
        try {
            while (rs.next()) {
                String atc = rs.getString(1);
                if (atc == null)
                    continue;
                if (!tm.containsKey(atc)) {
                    tm.put(atc, 0);
                }
                Integer integer = tm.get(atc);
                tm.put(atc, integer + 1);
            }
            rs.close();
        } catch (SQLException se) {
        }

        PersistentObject.getConnection().releaseStatement(stm);

        for (ATCCode atcCode : allATCCodes) {
            int foundElements = 0;

            ATCCode next = atcCodeService.getNextInHierarchy(atcCode);
            SortedMap<String, Integer> subMap;
            if (next != null) {
                subMap = tm.subMap(atcCode.atcCode, next.atcCode);
            } else {
                subMap = tm.tailMap(atcCode.atcCode);
            }

            for (Iterator<String> a = subMap.keySet().iterator(); a.hasNext();) {
                String val = a.next();
                foundElements += tm.get(val);
            }
            cache.put(atcCode.atcCode, foundElements);

            monitor.worked(1);
        }

        monitor.subTask("Persisting ATC Code product cache to database");
        // clear old caches
        NamedBlob2.cleanup(NAMED_BLOB_PREFIX, new TimeTool());

        // serialize the cache
        try {
            NamedBlob2 cacheStorage = NamedBlob2.create(determineBlobId(), false);
            ByteArrayOutputStream ba = new ByteArrayOutputStream();
            ObjectOutputStream oba = new ObjectOutputStream(ba);
            oba.writeObject(cache);
            oba.close();
            cacheStorage.putBytes(ba.toByteArray());
            ba.close();
            monitor.worked(1);
        } catch (IOException e) {
            log.error("Error on cache generation", e);
        }

        monitor.done();
    }

}