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}