001package net.sf.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.2 (University Course Timetabling)<br>
025 *          Copyright (C) 2006 - 2010 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     */
053    protected IdConvertor(String file) {
054        iFile = file;
055        load();
056    }
057
058    /** Get an instance of IdConvertor class. */
059    public static IdConvertor getInstance() {
060        if (sInstance == null)
061            sInstance = new IdConvertor(null);
062        return sInstance;
063    }
064
065    /** Convert id of given type. */
066    public String convert(String type, String id) {
067        synchronized (iConversion) {
068            HashMap<String, String> conversion = iConversion.get(type);
069            if (conversion == null) {
070                conversion = new HashMap<String, String>();
071                iConversion.put(type, conversion);
072            }
073            String newId = conversion.get(id);
074            if (newId == null) {
075                newId = String.valueOf(conversion.size() + 1);
076                conversion.put(id, newId);
077            }
078            return newId;
079        }
080    }
081    
082    /**
083     * Clear id conversion table.
084     */
085    public void clear() {
086        iConversion.clear();
087    }
088
089    /**
090     * Save id conversion file.
091     * @param file id file to save
092     */
093    public void save(File file) {
094        file.getParentFile().mkdirs();
095        Document document = DocumentHelper.createDocument();
096        Element root = document.addElement("id-convertor");
097        synchronized (iConversion) {
098            for (Map.Entry<String, HashMap<String, String>> entry : iConversion.entrySet()) {
099                String type = entry.getKey();
100                HashMap<String, String> conversion = entry.getValue();
101                Element convEl = root.addElement(type);
102                for (Map.Entry<String, String> idConv : conversion.entrySet()) {
103                    convEl.addElement("conv").addAttribute("old", idConv.getKey()).addAttribute("new",
104                            idConv.getValue());
105                }
106            }
107        }
108        FileOutputStream fos = null;
109        try {
110            fos = new FileOutputStream(file);
111            (new XMLWriter(fos, OutputFormat.createPrettyPrint())).write(document);
112            fos.flush();
113            fos.close();
114            fos = null;
115        } catch (Exception e) {
116            sLogger.error("Unable to save id conversions, reason: " + e.getMessage(), e);
117        } finally {
118            try {
119                if (fos != null)
120                    fos.close();
121            } catch (IOException e) {
122            }
123        }
124    }
125    
126    /**
127     * Save id conversion file. Name of the file needs to be provided by system
128     * property IdConvertor.File
129     */
130    public void save() {
131        if (iFile == null)
132            iFile = System.getProperty("IdConvertor.File");
133        if (iFile != null) save(new File(iFile));
134    }
135
136    /**
137     * Load id conversion file.
138     * @param file id file to load
139     */
140    public void load(File file) {
141        if (!file.exists()) return;
142        try {
143            Document document = (new SAXReader()).read(file);
144            Element root = document.getRootElement();
145            synchronized (iConversion) {
146                iConversion.clear();
147                for (Iterator<?> i = root.elementIterator(); i.hasNext();) {
148                    Element convEl = (Element) i.next();
149                    HashMap<String, String> conversion = new HashMap<String, String>();
150                    iConversion.put(convEl.getName(), conversion);
151                    for (Iterator<?> j = convEl.elementIterator("conv"); j.hasNext();) {
152                        Element e = (Element) j.next();
153                        conversion.put(e.attributeValue("old"), e.attributeValue("new"));
154                    }
155                }
156            }
157        } catch (Exception e) {
158            sLogger.error("Unable to load id conversions, reason: " + e.getMessage(), e);
159        }
160    }
161    
162    /**
163     * Load id conversion file. Name of the file needs to be provided by system
164     * property IdConvertor.File
165     */
166    public void load() {
167        if (iFile == null)
168            iFile = System.getProperty("IdConvertor.File");
169        if (iFile != null) load(new File(iFile));
170    }
171}