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}