    001package org.cpsolver.coursett;
    002
    003import java.io.File;
    004import java.io.FileOutputStream;
    005import java.io.IOException;
    006import java.util.HashMap;
    007import java.util.Iterator;
    008import java.util.Map;
    009
    010import org.dom4j.Document;
    011import org.dom4j.DocumentHelper;
    012import org.dom4j.Element;
    013import org.dom4j.io.OutputFormat;
    014import org.dom4j.io.SAXReader;
    015import org.dom4j.io.XMLWriter;
    016
    017/**
    018 * Conversion of ids to sequential numbers. This class is used by
    019 * {@link TimetableXMLSaver} to anonymise benchmark data sets. Conversion file
    020 * can be provided by IdConvertor.File system property (e.g.
    021 * -DIdConvertor.File=.\idconf.xml). <br>
    022 * <br>
    023 *
    024 * @author  Tomáš Müller
    025 * @version CourseTT 1.3 (University Course Timetabling)<br>
    026 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
    027 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    028 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    029 * <br>
    030 *          This library is free software; you can redistribute it and/or modify
    031 *          it under the terms of the GNU Lesser General Public License as
    032 *          published by the Free Software Foundation; either version 3 of the
    033 *          License, or (at your option) any later version. <br>
    034 * <br>
    035 *          This library is distributed in the hope that it will be useful, but
    036 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    037 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    038 *          Lesser General Public License for more details. <br>
    039 * <br>
    040 *          You should have received a copy of the GNU Lesser General Public
    041 *          License along with this library; if not see
    042 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    043 */
    044public class IdConvertor {
    045    private static org.apache.logging.log4j.Logger sLogger = org.apache.logging.log4j.LogManager.getLogger(IdConvertor.class);
    046    private static IdConvertor sInstance = null;
    047    private HashMap<String, HashMap<String, String>> iConversion = new HashMap<String, HashMap<String, String>>();
    048    private String iFile = null;
    049
    050    /**
    051     * Constructor -- use {@link IdConvertor#getInstance} to get an instance of
    052     * this class.
    053     * @param file file to load / save
    054     */
    055    public IdConvertor(String file) {
    056        iFile = file;
    057        load();
    058    }
    059
    060    /** Get an instance of IdConvertor class.
    061     * @return static instance
    062     **/
    063    public static IdConvertor getInstance() {
    064        if (sInstance == null)
    065            sInstance = new IdConvertor(null);
    066        return sInstance;
    067    }
    068
    069    /** Convert id of given type.
    070     * @param type object type
    071     * @param id unique id
    072     * @return serialized (obfuscated) id
    073     **/
    074    public String convert(String type, String id) {
    075        synchronized (iConversion) {
    076            HashMap<String, String> conversion = iConversion.get(type);
    077            if (conversion == null) {
    078                conversion = new HashMap<String, String>();
    079                iConversion.put(type, conversion);
    080            }
    081            String newId = conversion.get(id);
    082            if (newId == null) {
    083                newId = String.valueOf(conversion.size() + 1);
    084                conversion.put(id, newId);
    085            }
    086            return newId;
    087        }
    088    }
    089
    090    /**
    091     * Clear id conversion table.
    092     */
    093    public void clear() {
    094        iConversion.clear();
    095    }
    096
    097    /**
    098     * Save id conversion file.
    099     * @param file id file to save
    100     */
    101    public void save(File file) {
    102        file.getParentFile().mkdirs();
    103        Document document = DocumentHelper.createDocument();
    104        Element root = document.addElement("id-convertor");
    105        synchronized (iConversion) {
    106            for (Map.Entry<String, HashMap<String, String>> entry : iConversion.entrySet()) {
    107                String type = entry.getKey();
    108                HashMap<String, String> conversion = entry.getValue();
    109                Element convEl = root.addElement(type);
    110                for (Map.Entry<String, String> idConv : conversion.entrySet()) {
    111                    convEl.addElement("conv").addAttribute("old", idConv.getKey()).addAttribute("new",
    112                            idConv.getValue());
    113                }
    114            }
    115        }
    116        FileOutputStream fos = null;
    117        try {
    118            fos = new FileOutputStream(file);
    119            (new XMLWriter(fos, OutputFormat.createPrettyPrint())).write(document);
    120            fos.flush();
    121            fos.close();
    122            fos = null;
    123        } catch (Exception e) {
    124            sLogger.error("Unable to save id conversions, reason: " + e.getMessage(), e);
    125        } finally {
    126            try {
    127                if (fos != null)
    128                    fos.close();
    129            } catch (IOException e) {
    130            }
    131        }
    132    }
    133
    134    /**
    135     * Save id conversion file. Name of the file needs to be provided by system
    136     * property IdConvertor.File
    137     */
    138    public void save() {
    139        if (iFile == null)
    140            iFile = System.getProperty("IdConvertor.File");
    141        if (iFile != null) save(new File(iFile));
    142    }
    143
    144    /**
    145     * Load id conversion file.
    146     * @param file id file to load
    147     */
    148    public void load(File file) {
    149        if (!file.exists()) return;
    150        try {
    151            Document document = (new SAXReader()).read(file);
    152            Element root = document.getRootElement();
    153            synchronized (iConversion) {
    154                iConversion.clear();
    155                for (Iterator<?> i = root.elementIterator(); i.hasNext();) {
    156                    Element convEl = (Element) i.next();
    157                    HashMap<String, String> conversion = new HashMap<String, String>();
    158                    iConversion.put(convEl.getName(), conversion);
    159                    for (Iterator<?> j = convEl.elementIterator("conv"); j.hasNext();) {
    160                        Element e = (Element) j.next();
    161                        conversion.put(e.attributeValue("old"), e.attributeValue("new"));
    162                    }
    163                }
    164            }
    165        } catch (Exception e) {
    166            sLogger.error("Unable to load id conversions, reason: " + e.getMessage(), e);
    167        }
    168    }
    169
    170    /**
    171     * Load id conversion file. Name of the file needs to be provided by system
    172     * property IdConvertor.File
    173     */
    174    public void load() {
    175        if (iFile == null)
    176            iFile = System.getProperty("IdConvertor.File");
    177        if (iFile != null) load(new File(iFile));
    178    }
    179}