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