    001    package org.maltparser.core.config;
    002
    003    import java.io.BufferedInputStream;
    004    import java.io.BufferedOutputStream;
    005    import java.io.BufferedReader;
    006    import java.io.BufferedWriter;
    007    import java.io.File;
    008    import java.io.FileInputStream;
    009    import java.io.FileNotFoundException;
    010    import java.io.FileOutputStream;
    011    import java.io.FileReader;
    012    import java.io.FileWriter;
    013    import java.io.IOException;
    014    import java.io.InputStream;
    015    import java.io.InputStreamReader;
    016    import java.io.OutputStreamWriter;
    017    import java.io.UnsupportedEncodingException;
    018    import java.net.MalformedURLException;
    019    import java.net.URL;
    020    import java.util.Date;
    021    import java.util.Enumeration;
    022    import java.util.HashMap;
    023    import java.util.HashSet;
    024    import java.util.SortedSet;
    025    import java.util.TreeSet;
    026    import java.util.jar.JarEntry;
    027    import java.util.jar.JarFile;
    028    import java.util.jar.JarInputStream;
    029    import java.util.jar.JarOutputStream;
    030
    031    import org.maltparser.core.config.version.Versioning;
    032    import org.maltparser.core.exception.MaltChainedException;
    033    import org.maltparser.core.helper.SystemInfo;
    034    import org.maltparser.core.helper.SystemLogger;
    035    import org.maltparser.core.helper.Util;
    036    import org.maltparser.core.io.dataformat.DataFormatInstance;
    037    import org.maltparser.core.io.dataformat.DataFormatManager;
    038    import org.maltparser.core.options.OptionManager;
    039    import org.maltparser.core.symbol.SymbolTableHandler;
    040    import org.maltparser.core.symbol.trie.TrieSymbolTableHandler;
    041
    042
    043    /**
    044    * This class contains methods for handle the configuration directory.
    045    *
    046    * @author Johan Hall
    047    */
    048    public class ConfigurationDir  {
    049            protected static final int BUFFER = 4096;
    050            protected File configDirectory;
    051            protected String name;
    052            protected String type;
    053            protected File workingDirectory;
    054            protected URL url = null;
    055            protected int containerIndex;
    056            protected BufferedWriter infoFile = null;
    057            protected String createdByMaltParserVersion;
    058
    059            private SymbolTableHandler symbolTables;
    060            private DataFormatManager dataFormatManager;
    061            private HashMap<String,DataFormatInstance> dataFormatInstances;
    062
    063
    064            /**
    065             * Creates a configuration directory from a mco-file specified by an URL.
    066             *
    067             * @param url   an URL to a mco-file
    068             * @throws MaltChainedException
    069             */
    070            public ConfigurationDir(URL url) throws MaltChainedException {
    071                    initWorkingDirectory();
    072                    setUrl(url);
    073                    initNameNTypeFromInfoFile(url);
    074    //              initData();
    075            }
    076
    077            /**
    078             * Creates a new configuration directory or a configuration directory from a mco-file
    079             *
    080             * @param name  the name of the configuration
    081             * @param type  the type of configuration
    082             * @param containerIndex        the container index
    083             * @throws MaltChainedException
    084             */
    085            public ConfigurationDir(String name, String type, int containerIndex) throws MaltChainedException {
    086                    setContainerIndex(containerIndex);
    087
    088                    initWorkingDirectory();
    089                    if (name != null && name.length() > 0 && type != null && type.length() > 0) {
    090                            setName(name);
    091                            setType(type);
    092                    } else {
    093                            throw new ConfigurationException("The configuration name is not specified. ");
    094                    }
    095                    setConfigDirectory(new File(workingDirectory.getPath()+File.separator+getName()));
    096            }
    097
    098            public void initDataFormat() throws MaltChainedException {
    099                    String inputFormatName = OptionManager.instance().getOptionValue(containerIndex, "input", "format").toString().trim();
    100                    String outputFormatName = OptionManager.instance().getOptionValue(containerIndex, "output", "format").toString().trim();
    101    //              SystemLogger.logger().info(inputFormatName + "\n");
    102    //              SystemLogger.logger().info(outputFormatName + "\n");
    103                    if (configDirectory != null && configDirectory.exists()) {
    104                            if (outputFormatName.length() == 0 || inputFormatName.equals(outputFormatName)) {
    105                                    URL inputFormatURL = Util.findURLinJars(inputFormatName);
    106                                    if (inputFormatURL != null) {
    107                                            outputFormatName = inputFormatName = this.copyToConfig(inputFormatURL);
    108                                    } else {
    109                                            outputFormatName = inputFormatName = this.copyToConfig(inputFormatName);
    110                                    }
    111                            } else {
    112                                    URL inputFormatURL = Util.findURLinJars(inputFormatName);
    113                                    if (inputFormatURL != null) {
    114                                            inputFormatName = this.copyToConfig(inputFormatURL);
    115                                    } else {
    116                                            inputFormatName = this.copyToConfig(inputFormatName);
    117                                    }
    118                                    URL outputFormatURL = Util.findURLinJars(outputFormatName);
    119                                    if (inputFormatURL != null) {
    120                                            outputFormatName = this.copyToConfig(outputFormatURL);
    121                                    } else {
    122                                            outputFormatName = this.copyToConfig(outputFormatName);
    123                                    }
    124                            }
    125                            OptionManager.instance().overloadOptionValue(containerIndex, "input", "format", inputFormatName);
    126                    } else {
    127                            if (outputFormatName.length() == 0) {
    128                                    outputFormatName = inputFormatName;
    129                            }
    130                    }
    131                    dataFormatInstances = new HashMap<String, DataFormatInstance>(3);
    132
    133                    URL inURL = findURL(inputFormatName);
    134                    URL outURL = findURL(outputFormatName);
    135
    136
    137                    if (outURL != null) {
    138                            try {
    139                                    InputStream is = outURL.openStream();
    140                            } catch (FileNotFoundException e) {
    141                                    outURL = Util.findURL(outputFormatName);
    142                            } catch (IOException e) {
    143                                    outURL = Util.findURL(outputFormatName);
    144                            }
    145                    } else {
    146                            outURL = Util.findURL(outputFormatName);
    147                    }
    148
    149                    dataFormatManager = new DataFormatManager(inURL, outURL);
    150                    symbolTables = new TrieSymbolTableHandler();
    151            }
    152
    153            private URL findURL(String specModelFileName) throws MaltChainedException {
    154                    URL url = null;
    155                    File specFile = this.getFile(specModelFileName);
    156                    if (specFile.exists()) {
    157                            try {
    158                                    url = new URL("file:///"+specFile.getAbsolutePath());
    159                            } catch (MalformedURLException e) {
    160                                    throw new MaltChainedException("Malformed URL: "+specFile, e);
    161                            }
    162                    } else {
    163                            url = this.getConfigFileEntryURL(specModelFileName);
    164                    }
    165                    return url;
    166            }
    167
    168            /**
    169             * Creates an output stream writer, where the corresponding file will be included in the configuration directory
    170             *
    171             * @param fileName      a file name
    172             * @param charSet       a char set
    173             * @return      an output stream writer for writing to a file within the configuration directory
    174             * @throws MaltChainedException
    175             */
    176            public OutputStreamWriter getOutputStreamWriter(String fileName, String charSet) throws MaltChainedException {
    177                    try {
    178                            return new OutputStreamWriter(new FileOutputStream(configDirectory.getPath()+File.separator+fileName), charSet);
    179                    } catch (FileNotFoundException e) {
    180                            throw new ConfigurationException("The file '"+fileName+"' cannot be created. ", e);
    181                    } catch (UnsupportedEncodingException e) {
    182                            throw new ConfigurationException("The char set '"+charSet+"' is not supported. ", e);
    183                    }
    184            }
    185
    186            /**
    187             * Creates an output stream writer, where the corresponding file will be included in the
    188             * configuration directory. Uses UTF-8 for character encoding.
    189             *
    190             * @param fileName      a file name
    191             * @return an output stream writer for writing to a file within the configuration directory
    192             * @throws MaltChainedException
    193             */
    194            public OutputStreamWriter getOutputStreamWriter(String fileName) throws MaltChainedException {
    195                    try {
    196                            return new OutputStreamWriter(new FileOutputStream(configDirectory.getPath()+File.separator+fileName, true), "UTF-8");
    197                    } catch (FileNotFoundException e) {
    198                            throw new ConfigurationException("The file '"+fileName+"' cannot be created. ", e);
    199                    } catch (UnsupportedEncodingException e) {
    200                            throw new ConfigurationException("The char set 'UTF-8' is not supported. ", e);
    201                    }
    202            }
    203            /**
    204             * This method acts the same as getOutputStreamWriter with the difference that the writer append in the file
    205             * if it already exists instead of deleting the previous content before starting to write.
    206             *
    207             * @param fileName      a file name
    208             * @return an output stream writer for writing to a file within the configuration directory
    209             * @throws MaltChainedException
    210             */
    211            public OutputStreamWriter getAppendOutputStreamWriter(String fileName) throws MaltChainedException {
    212                    try {
    213                            return new OutputStreamWriter(new FileOutputStream(configDirectory.getPath()+File.separator+fileName, true), "UTF-8");
    214                    } catch (FileNotFoundException e) {
    215                            throw new ConfigurationException("The file '"+fileName+"' cannot be created. ", e);
    216                    } catch (UnsupportedEncodingException e) {
    217                            throw new ConfigurationException("The char set 'UTF-8' is not supported. ", e);
    218                    }
    219            }
    220
    221            /**
    222             * Creates an input stream reader for reading a file within the configuration directory
    223             *
    224             * @param fileName      a file name
    225             * @param charSet       a char set
    226             * @return an input stream reader for reading a file within the configuration directory
    227             * @throws MaltChainedException
    228             */
    229            public InputStreamReader getInputStreamReader(String fileName, String charSet) throws MaltChainedException {
    230                    try {
    231                            return new InputStreamReader(new FileInputStream(configDirectory.getPath()+File.separator+fileName), charSet);
    232                    } catch (FileNotFoundException e) {
    233                            throw new ConfigurationException("The file '"+fileName+"' cannot be found. ", e);
    234                    } catch (UnsupportedEncodingException e) {
    235                            throw new ConfigurationException("The char set '"+charSet+"' is not supported. ", e);
    236                    }
    237            }
    238
    239            /**
    240             * Creates an input stream reader for reading a file within the configuration directory.
    241             * Uses UTF-8 for character encoding.
    242             *
    243             * @param fileName      a file name
    244             * @return      an input stream reader for reading a file within the configuration directory
    245             * @throws MaltChainedException
    246             */
    247            public InputStreamReader getInputStreamReader(String fileName) throws MaltChainedException {
    248                    return getInputStreamReader(fileName, "UTF-8");
    249            }
    250
    251            public JarEntry getConfigFileEntry(String fileName) throws MaltChainedException {
    252                    File mcoPath = new File(workingDirectory.getPath()+File.separator+getName()+".mco");
    253                    try {
    254                            JarFile mcoFile = new JarFile(mcoPath.getAbsolutePath());
    255                            JarEntry entry = mcoFile.getJarEntry(getName()+'/'+fileName);
    256                            if (entry == null) {
    257                                    entry = mcoFile.getJarEntry(getName()+'\\'+fileName);
    258                            }
    259                            return entry;
    260                    } catch (FileNotFoundException e) {
    261                            throw new ConfigurationException("The file entry '"+fileName+"' in mco-file '"+mcoPath+"' cannot be found. ", e);
    262                    } catch (IOException e) {
    263                            throw new ConfigurationException("The file entry '"+fileName+"' in mco-file '"+mcoPath+"' cannot be found. ", e);
    264                    }
    265            }
    266
    267            public InputStreamReader getInputStreamReaderFromConfigFileEntry(String fileName, String charSet) throws MaltChainedException {
    268                    File mcoPath = new File(workingDirectory.getPath()+File.separator+getName()+".mco");
    269                    try {
    270                            JarFile mcoFile = new JarFile(mcoPath.getAbsolutePath());
    271                            JarEntry entry = mcoFile.getJarEntry(getName()+'/'+fileName);
    272                            if (entry == null) {
    273                                    entry = mcoFile.getJarEntry(getName()+'\\'+fileName);
    274                            }
    275                            if (entry == null) {
    276                                    throw new FileNotFoundException();
    277                            }
    278                            return new InputStreamReader(mcoFile.getInputStream(entry),  charSet);
    279                    } catch (FileNotFoundException e) {
    280                            throw new ConfigurationException("The file entry '"+fileName+"' in the mco file '"+mcoPath+"' cannot be found. ", e);
    281                    } catch (UnsupportedEncodingException e) {
    282                            throw new ConfigurationException("The char set '"+charSet+"' is not supported. ", e);
    283                    } catch (IOException e) {
    284                            throw new ConfigurationException("The file entry '"+fileName+"' in the mco file '"+mcoPath+"' cannot be loaded. ", e);
    285                    }
    286            }
    287
    288            public InputStreamReader getInputStreamReaderFromConfigFile(String fileName) throws MaltChainedException {
    289                    return getInputStreamReaderFromConfigFileEntry(fileName, "UTF-8");
    290            }
    291
    292            /**
    293             * Returns a file handler object of a file within the configuration directory
    294             *
    295             * @param fileName      a file name
    296             * @return      a file handler object of a file within the configuration directory
    297             * @throws MaltChainedException
    298             */
    299            public File getFile(String fileName) throws MaltChainedException {
    300                    return new File(configDirectory.getPath()+File.separator+fileName);
    301            }
    302
    303            public URL getConfigFileEntryURL(String fileName) throws MaltChainedException {
    304                    File mcoPath = new File(workingDirectory.getPath()+File.separator+getName()+".mco");
    305                    try {
    306                            if (!mcoPath.exists()) {
    307                                    throw new ConfigurationException("Couldn't find mco-file '" +mcoPath.getAbsolutePath()+ "'");
    308                            }
    309    //                      new URL("file", null, mcoPath.getAbsolutePath());
    310                            URL url = new URL("jar:"+new URL("file", null, mcoPath.getAbsolutePath())+"!/"+getName()+'/'+fileName + "\n");
    311                            try {
    312                                    InputStream is = url.openStream();
    313                                    is.close();
    314                            } catch (IOException e) {
    315                                    url = new URL("jar:"+new URL("file", null, mcoPath.getAbsolutePath())+"!/"+getName()+'\\'+fileName + "\n");
    316                            }
    317                            return url;
    318                    } catch (MalformedURLException e) {
    319                            throw new ConfigurationException("Couldn't find the URL '" +"jar:"+mcoPath.getAbsolutePath()+"!/"+getName()+'/'+fileName+ "'", e);
    320                    }
    321            }
    322
    323        /**
    324         * Copies a file into the configuration directory.
    325         *
    326         * @param source    a path to file
    327         * @throws MaltChainedException
    328         */
    329        public String copyToConfig(File source) throws MaltChainedException {
    330            byte[] readBuffer = new byte[BUFFER];
    331            String destination = configDirectory.getPath()+File.separator+source.getName();
    332            try {
    333                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
    334                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destination), BUFFER);
    335
    336                    int n = 0;
    337                        while ((n = bis.read(readBuffer, 0, BUFFER)) != -1) {
    338                            bos.write(readBuffer, 0, n);
    339                        }
    340                    bos.flush();
    341                    bos.close();
    342                    bis.close();
    343                    } catch (FileNotFoundException e) {
    344                            throw new ConfigurationException("The source file '"+source+"' cannot be found or the destination file '"+destination+"' cannot be created when coping the file. ", e);
    345                    } catch (IOException e) {
    346                            throw new ConfigurationException("The source file '"+source+"' cannot be copied to destination '"+destination+"'. ", e);
    347                    }
    348                    return source.getName();
    349        }
    350
    351
    352        public String copyToConfig(String fileUrl) throws MaltChainedException {
    353            URL url = Util.findURL(fileUrl);
    354            if (url == null) {
    355                    throw new ConfigurationException("The file or URL '"+fileUrl+"' could not be found. ");
    356            }
    357            return copyToConfig(url);
    358        }
    359
    360        public String copyToConfig(URL url) throws MaltChainedException {
    361            if (url == null) {
    362                    throw new ConfigurationException("URL could not be found. ");
    363            }
    364            byte[] readBuffer = new byte[BUFFER];
    365            String destFileName = url.getPath();
    366                    int indexSlash = destFileName.lastIndexOf('/');
    367                    if (indexSlash == -1) {
    368                            indexSlash = destFileName.lastIndexOf('\\');
    369                    }
    370
    371                    if (indexSlash != -1) {
    372                            destFileName = destFileName.substring(indexSlash+1);
    373                    }
    374
    375            String destination = configDirectory.getPath()+File.separator+destFileName;
    376            try {
    377                    BufferedInputStream bis = new BufferedInputStream(url.openStream());
    378                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destination), BUFFER);
    379
    380                    int n = 0;
    381                        while ((n = bis.read(readBuffer, 0, BUFFER)) != -1) {
    382                            bos.write(readBuffer, 0, n);
    383                        }
    384                    bos.flush();
    385                    bos.close();
    386                    bis.close();
    387                    } catch (FileNotFoundException e) {
    388                            throw new ConfigurationException("The destination file '"+destination+"' cannot be created when coping the file. ", e);
    389                    } catch (IOException e) {
    390                            throw new ConfigurationException("The URL '"+url+"' cannot be copied to destination '"+destination+"'. ", e);
    391                    }
    392                    return destFileName;
    393        }
    394
    395
    396            /**
    397             * Removes the configuration directory, if it exists and it contains a .info file.
    398             *
    399             * @throws MaltChainedException
    400             */
    401            public void deleteConfigDirectory() throws MaltChainedException {
    402                    if (!configDirectory.exists()) {
    403                            return;
    404                    }
    405                    File infoFile = new File(configDirectory.getPath()+File.separator+getName()+"_"+getType()+".info");
    406                    if (infoFile.exists()) {
    407                            deleteConfigDirectory(configDirectory);
    408                    } else {
    409                            throw new ConfigurationException("There exists a directory that is not a MaltParser configuration directory. ");
    410                    }
    411            }
    412
    413            private void deleteConfigDirectory(File directory) throws MaltChainedException {
    414                    if (directory.exists()) {
    415                            File[] files = directory.listFiles();
    416                            for (int i = 0; i < files.length; i++) {
    417                                    if (files[i].isDirectory()) {
    418                                            deleteConfigDirectory(files[i]);
    419                                    } else {
    420                                            files[i].delete();
    421                                    }
    422                            }
    423                    } else {
    424                            throw new ConfigurationException("The directory '"+directory.getPath()+ "' cannot be found. ");
    425                    }
    426                    directory.delete();
    427            }
    428
    429            /**
    430             * Returns a file handler object for the configuration directory
    431             *
    432             * @return a file handler object for the configuration directory
    433             */
    434            public File getConfigDirectory() {
    435                    return configDirectory;
    436            }
    437
    438            protected void setConfigDirectory(File dir) {
    439                    this.configDirectory = dir;
    440            }
    441
    442            /**
    443             * Creates the configuration directory
    444             *
    445             * @throws MaltChainedException
    446             */
    447            public void createConfigDirectory() throws MaltChainedException {
    448                    checkConfigDirectory();
    449                    configDirectory.mkdir();
    450                    createInfoFile();
    451            }
    452
    453            protected void checkConfigDirectory()  throws MaltChainedException {
    454                    if (configDirectory.exists() && !configDirectory.isDirectory()) {
    455                            throw new ConfigurationException("The configuration directory name already exists and is not a directory. ");
    456                    }
    457
    458                    if (configDirectory.exists()) {
    459                            deleteConfigDirectory();
    460                    }
    461            }
    462
    463            protected void createInfoFile() throws MaltChainedException {
    464                    infoFile = new BufferedWriter(getOutputStreamWriter(getName()+"_"+getType()+".info"));
    465                    try {
    466                            infoFile.write("CONFIGURATION\n");
    467                            infoFile.write("Configuration name:   "+getName()+"\n");
    468                            infoFile.write("Configuration type:   "+getType()+"\n");
    469                            infoFile.write("Created:              "+new Date(System.currentTimeMillis())+"\n");
    470
    471                            infoFile.write("\nSYSTEM\n");
    472                            infoFile.write("Operating system architecture: "+System.getProperty("os.arch")+"\n");
    473                            infoFile.write("Operating system name:         "+System.getProperty("os.name")+"\n");
    474                            infoFile.write("JRE vendor name:               "+System.getProperty("java.vendor")+"\n");
    475                            infoFile.write("JRE version number:            "+System.getProperty("java.version")+"\n");
    476
    477                            infoFile.write("\nMALTPARSER\n");
    478                            infoFile.write("Version:                       "+SystemInfo.getVersion()+"\n");
    479                            infoFile.write("Build date:                    "+SystemInfo.getBuildDate()+"\n");
    480                            HashSet<String> excludeGroups = new HashSet<String>();
    481                            excludeGroups.add("system");
    482                            infoFile.write("\nSETTINGS\n");
    483                            infoFile.write(OptionManager.instance().toStringPrettyValues(containerIndex, excludeGroups));
    484                            infoFile.flush();
    485                    } catch (IOException e) {
    486                            throw new ConfigurationException("Could not create the maltparser info file. ");
    487                    }
    488            }
    489
    490            /**
    491             * Returns a writer to the configuration information file
    492             *
    493             * @return      a writer to the configuration information file
    494             * @throws MaltChainedException
    495             */
    496            public BufferedWriter getInfoFileWriter() throws MaltChainedException {
    497                    return infoFile;
    498            }
    499
    500            /**
    501             * Creates the malt configuration file (.mco). This file is compressed.
    502             *
    503             * @throws MaltChainedException
    504             */
    505            public void createConfigFile() throws MaltChainedException {
    506                    try {
    507                            JarOutputStream jos = new JarOutputStream(new FileOutputStream(workingDirectory.getPath()+File.separator+getName()+".mco"));
    508    //                      configLogger.info("Creates configuration file '"+workingDirectory.getPath()+File.separator+getName()+".mco' ...\n");
    509                            createConfigFile(configDirectory.getPath(), jos);
    510                            jos.close();
    511                    } catch (FileNotFoundException e) {
    512                            throw new ConfigurationException("The maltparser configurtation file '"+workingDirectory.getPath()+File.separator+getName()+".mco"+"' cannot be found. ", e);
    513                    } catch (IOException e) {
    514                            throw new ConfigurationException("The maltparser configurtation file '"+workingDirectory.getPath()+File.separator+getName()+".mco"+"' cannot be created. ", e);
    515                    }
    516            }
    517
    518            private void createConfigFile(String directory, JarOutputStream jos) throws MaltChainedException {
    519            byte[] readBuffer = new byte[BUFFER];
    520                    try {
    521                            File zipDir = new File(directory);
    522                            String[] dirList = zipDir.list();
    523
    524                            int bytesIn = 0;
    525
    526                            for (int i = 0; i < dirList.length; i++) {
    527                                    File f = new File(zipDir, dirList[i]);
    528                                    if (f.isDirectory()) {
    529                                            String filePath = f.getPath();
    530                                            createConfigFile(filePath, jos);
    531                                            continue;
    532                                    }
    533
    534                                    FileInputStream fis = new FileInputStream(f);
    535
    536                                    String entryPath = f.getPath().substring(workingDirectory.getPath().length()+1);
    537                                    entryPath = entryPath.replace('\\', '/');
    538                                    JarEntry entry = new JarEntry(entryPath);
    539                                    jos.putNextEntry(entry);
    540
    541                                    while ((bytesIn = fis.read(readBuffer)) != -1) {
    542                                            jos.write(readBuffer, 0, bytesIn);
    543                                    }
    544
    545                                    fis.close();
    546                            }
    547                    } catch (FileNotFoundException e) {
    548                            throw new ConfigurationException("The directory '"+directory+"' cannot be found. ", e);
    549                    } catch (IOException e) {
    550                            throw new ConfigurationException("The directory '"+directory+"' cannot be compressed into a mco file. ", e);
    551                    }
    552            }
    553
    554
    555            public void copyConfigFile(File in, File out, Versioning versioning) throws MaltChainedException {
    556                    try {
    557                            JarFile jar = new JarFile(in);
    558                            JarOutputStream tempJar = new JarOutputStream(new FileOutputStream(out));
    559                    byte[] buffer = new byte[BUFFER];
    560                    int bytesRead;
    561                    StringBuilder sb = new StringBuilder();
    562
    563                    for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements(); ) {
    564                        JarEntry inEntry = (JarEntry) entries.nextElement();
    565                        InputStream entryStream = jar.getInputStream(inEntry);
    566                        JarEntry outEntry = versioning.getJarEntry(inEntry);
    567
    568                        if (!versioning.hasChanges(inEntry, outEntry)) {
    569                                tempJar.putNextEntry(outEntry);
    570                                while ((bytesRead = entryStream.read(buffer)) != -1) {
    571                                    tempJar.write(buffer, 0, bytesRead);
    572                                }
    573                        } else {
    574                            tempJar.putNextEntry(outEntry);
    575                            BufferedReader br = new BufferedReader(new InputStreamReader(entryStream));
    576                            String line = null;
    577                            sb.setLength(0);
    578                            while ((line = br.readLine()) != null) {
    579                                    sb.append(line);
    580                                    sb.append('\n');
    581                            }
    582                            String outString = versioning.modifyJarEntry(inEntry, outEntry, sb);
    583                            tempJar.write(outString.getBytes());
    584                        }
    585                    }
    586                    if (versioning.getFeatureModelXML() != null && versioning.getFeatureModelXML().startsWith("/appdata")) {
    587                            int index = versioning.getFeatureModelXML().lastIndexOf('/');
    588                    BufferedInputStream bis = new BufferedInputStream(Util.findURLinJars(versioning.getFeatureModelXML()).openStream());
    589                    tempJar.putNextEntry(new JarEntry(versioning.getNewConfigName()+"/" +versioning.getFeatureModelXML().substring(index+1)));
    590                    int n = 0;
    591                        while ((n = bis.read(buffer, 0, BUFFER)) != -1) {
    592                            tempJar.write(buffer, 0, n);
    593                        }
    594                    bis.close();
    595                    }
    596                    if (versioning.getInputFormatXML() != null && versioning.getInputFormatXML().startsWith("/appdata")) {
    597                            int index = versioning.getInputFormatXML().lastIndexOf('/');
    598                    BufferedInputStream bis = new BufferedInputStream(Util.findURLinJars(versioning.getInputFormatXML()).openStream());
    599                    tempJar.putNextEntry(new JarEntry(versioning.getNewConfigName()+"/" +versioning.getInputFormatXML().substring(index+1)));
    600                    int n = 0;
    601                        while ((n = bis.read(buffer, 0, BUFFER)) != -1) {
    602                            tempJar.write(buffer, 0, n);
    603                        }
    604                    bis.close();
    605                    }
    606                    tempJar.flush();
    607                    tempJar.close();
    608                    jar.close();
    609                    } catch (IOException e) {
    610                            throw new ConfigurationException("", e);
    611                    }
    612            }
    613
    614        protected void initNameNTypeFromInfoFile(URL url) throws MaltChainedException {
    615                    if (url == null) {
    616                            throw new ConfigurationException("The URL cannot be found. ");
    617                    }
    618                    try {
    619                            JarEntry je;
    620                            JarInputStream jis = new JarInputStream(url.openConnection().getInputStream());
    621                            while ((je = jis.getNextJarEntry()) != null) {
    622                                    String entryName = je.getName();
    623                                    if (entryName.endsWith(".info")) {
    624                                            int indexUnderScore = entryName.lastIndexOf('_');
    625                                            int indexSeparator = entryName.lastIndexOf(File.separator);
    626                                            if (indexSeparator == -1) {
    627                                                    indexSeparator = entryName.lastIndexOf('/');
    628                                            }
    629                                            if (indexSeparator == -1) {
    630                                                    indexSeparator = entryName.lastIndexOf('\\');
    631                                            }
    632                                            int indexDot = entryName.lastIndexOf('.');
    633                                            if (indexUnderScore == -1 || indexDot == -1) {
    634                                                    throw new ConfigurationException("Could not find the configuration name and type from the URL '"+url.toString()+"'. ");
    635                                            }
    636                                            setName(entryName.substring(indexSeparator+1, indexUnderScore));
    637                                            setType(entryName.substring(indexUnderScore+1, indexDot));
    638                                            setConfigDirectory(new File(workingDirectory.getPath()+File.separator+getName()));
    639                                            jis.close();
    640                                            return;
    641                                    }
    642                            }
    643
    644                    } catch (IOException e) {
    645                            throw new ConfigurationException("Could not find the configuration name and type from the URL '"+url.toString()+"'. ", e);
    646                    }
    647        }
    648
    649        /**
    650         * Prints the content of the configuration information file to the system logger
    651         *
    652         * @throws MaltChainedException
    653         */
    654        public void echoInfoFile() throws MaltChainedException {
    655            checkConfigDirectory();
    656            JarInputStream jis;
    657            try {
    658                    if (url == null) {
    659                            jis = new JarInputStream(new FileInputStream(workingDirectory.getPath()+File.separator+getName()+".mco"));
    660                    } else {
    661                            jis = new JarInputStream(url.openConnection().getInputStream());
    662                    }
    663                            JarEntry je;
    664
    665                            while ((je = jis.getNextJarEntry()) != null) {
    666                            String entryName = je.getName();
    667
    668                            if (entryName.endsWith(getName()+"_"+getType()+".info")) {
    669                                    int c;
    670                                        while ((c = jis.read()) != -1) {
    671                                            SystemLogger.logger().info((char)c);
    672                                        }
    673                            }
    674                            }
    675                    jis.close();
    676            } catch (FileNotFoundException e) {
    677                    throw new ConfigurationException("Could not print configuration information file. The configuration file '"+workingDirectory.getPath()+File.separator+getName()+".mco"+"' cannot be found. ", e);
    678            } catch (IOException e) {
    679                            throw new ConfigurationException("Could not print configuration information file. ", e);
    680                    }
    681
    682        }
    683
    684        /**
    685         * Unpacks the malt configuration file (.mco).
    686         *
    687         * @throws MaltChainedException
    688         */
    689        public void unpackConfigFile() throws MaltChainedException {
    690            checkConfigDirectory();
    691            JarInputStream jis;
    692            try {
    693                    if (url == null) {
    694                            jis = new JarInputStream(new FileInputStream(workingDirectory.getPath()+File.separator+getName()+".mco"));
    695                    } else {
    696                            jis = new JarInputStream(url.openConnection().getInputStream());
    697                    }
    698                    unpackConfigFile(jis);
    699                    jis.close();
    700            } catch (FileNotFoundException e) {
    701                    throw new ConfigurationException("Could not unpack configuration. The configuration file '"+workingDirectory.getPath()+File.separator+getName()+".mco"+"' cannot be found. ", e);
    702            } catch (IOException e) {
    703                    if (configDirectory.exists()) {
    704                            deleteConfigDirectory();
    705                    }
    706                            throw new ConfigurationException("Could not unpack configuration. ", e);
    707                    }
    708            initCreatedByMaltParserVersionFromInfoFile();
    709        }
    710
    711        protected void unpackConfigFile(JarInputStream jis) throws MaltChainedException {
    712                    try {
    713                            JarEntry je;
    714                            byte[] readBuffer = new byte[BUFFER];
    715                    SortedSet<String> directoryCache  = new TreeSet<String>();
    716                            while ((je = jis.getNextJarEntry()) != null) {
    717                            String entryName = je.getName();
    718
    719                            if (entryName.startsWith("/")) {
    720                                    entryName = entryName.substring(1);
    721                            }
    722                            if (entryName.endsWith(File.separator) || entryName.endsWith("/")) {
    723                                return;
    724                            }
    725                            int index = -1;
    726                            if (File.separator.equals("\\")) {
    727                                    entryName = entryName.replace('/', '\\');
    728                                    index = entryName.lastIndexOf("\\");
    729                            } else if (File.separator.equals("/")) {
    730                                    entryName = entryName.replace('\\', '/');
    731                                    index = entryName.lastIndexOf("/");
    732                            }
    733                            if (index > 0) {
    734                                String dirName = entryName.substring(0, index);
    735                                if (!directoryCache.contains(dirName)) {
    736                                    File directory = new File(workingDirectory.getPath()+File.separator+dirName);
    737                                    if (!(directory.exists() && directory.isDirectory())) {
    738                                        if (!directory.mkdirs()) {
    739                                            throw new ConfigurationException("Unable to make directory '" + dirName +"'. ");
    740                                        }
    741                                        directoryCache.add(dirName);
    742                                    }
    743                                }
    744                            }
    745
    746                            if (new File(workingDirectory.getPath()+File.separator+entryName).isDirectory() && new File(workingDirectory.getPath()+File.separator+entryName).exists()) {
    747                                    continue;
    748                            }
    749                            BufferedOutputStream bos;
    750                            try {
    751                                    bos = new BufferedOutputStream(new FileOutputStream(workingDirectory.getPath()+File.separator+entryName), BUFFER);
    752                            } catch (FileNotFoundException e) {
    753                                            throw new ConfigurationException("Could not unpack configuration. The file '"+workingDirectory.getPath()+File.separator+entryName+"' cannot be unpacked. ", e);
    754                            }
    755                                    int n = 0;
    756                                while ((n = jis.read(readBuffer, 0, BUFFER)) != -1) {
    757                                    bos.write(readBuffer, 0, n);
    758                                }
    759                                bos.flush();
    760                                bos.close();
    761                            }
    762                    } catch (IOException e) {
    763                            throw new ConfigurationException("Could not unpack configuration. ", e);
    764                    }
    765        }
    766
    767            /**
    768             * Returns the name of the configuration directory
    769             *
    770             * @return the name of the configuration directory
    771             */
    772            public String getName() {
    773                    return name;
    774            }
    775
    776            protected void setName(String name) {
    777                    this.name = name;
    778            }
    779
    780            /**
    781             * Returns the type of the configuration directory
    782             *
    783             * @return the type of the configuration directory
    784             */
    785            public String getType() {
    786                    return type;
    787            }
    788
    789            protected void setType(String type) {
    790                    this.type = type;
    791            }
    792
    793            /**
    794             * Returns a file handler object for the working directory
    795             *
    796             * @return a file handler object for the working directory
    797             */
    798            public File getWorkingDirectory() {
    799                    return workingDirectory;
    800            }
    801
    802            /**
    803             * Initialize the working directory
    804             *
    805             * @throws MaltChainedException
    806             */
    807            public void initWorkingDirectory() throws MaltChainedException {
    808                    try {
    809                            initWorkingDirectory(OptionManager.instance().getOptionValue(0, "config", "workingdir").toString());
    810                    } catch (NullPointerException e) {
    811                            throw new ConfigurationException("The configuration cannot be found.", e);
    812                    }
    813            }
    814
    815            /**
    816             * Initialize the working directory according to the path. If the path is equals to "user.dir" or current directory, then the current directory
    817             *  will be the working directory.
    818             *
    819             * @param pathPrefixString      the path to the working directory
    820             * @throws MaltChainedException
    821             */
    822            public void initWorkingDirectory(String pathPrefixString) throws MaltChainedException {
    823                    if (pathPrefixString == null || pathPrefixString.equalsIgnoreCase("user.dir") || pathPrefixString.equalsIgnoreCase(".")) {
    824                            workingDirectory = new File(System.getProperty("user.dir"));
    825                    } else {
    826                            workingDirectory = new File(pathPrefixString);
    827                    }
    828
    829                    if (workingDirectory == null || !workingDirectory.isDirectory()) {
    830                            new ConfigurationException("The specified working directory '"+pathPrefixString+"' is not a directory. ");
    831                    }
    832            }
    833
    834            /**
    835             * Returns the URL to the malt configuration file (.mco)
    836             *
    837             * @return the URL to the malt configuration file (.mco)
    838             */
    839            public URL getUrl() {
    840                    return url;
    841            }
    842
    843            protected void setUrl(URL url) {
    844                    this.url = url;
    845            }
    846
    847            /**
    848             * Returns the option container index
    849             *
    850             * @return the option container index
    851             */
    852            public int getContainerIndex() {
    853                    return containerIndex;
    854            }
    855
    856            /**
    857             * Sets the option container index
    858             *
    859             * @param containerIndex a option container index
    860             */
    861            public void setContainerIndex(int containerIndex) {
    862                    this.containerIndex = containerIndex;
    863            }
    864
    865            /**
    866             * Returns the version number of MaltParser which created the malt configuration file (.mco)
    867             *
    868             * @return the version number of MaltParser which created the malt configuration file (.mco)
    869             */
    870            public String getCreatedByMaltParserVersion() {
    871                    return createdByMaltParserVersion;
    872            }
    873
    874            /**
    875             * Sets the version number of MaltParser which created the malt configuration file (.mco)
    876             *
    877             * @param createdByMaltParserVersion a version number of MaltParser
    878             */
    879            public void setCreatedByMaltParserVersion(String createdByMaltParserVersion) {
    880                    this.createdByMaltParserVersion = createdByMaltParserVersion;
    881            }
    882
    883            public void initCreatedByMaltParserVersionFromInfoFile() throws MaltChainedException {
    884                    try {
    885                            BufferedReader br = new BufferedReader(getInputStreamReaderFromConfigFileEntry(getName()+"_"+getType()+".info", "UTF-8"));
    886                            String line = null;
    887                            while ((line = br.readLine()) != null) {
    888                                    if (line.startsWith("Version:                       ")) {
    889                                            setCreatedByMaltParserVersion(line.substring(31));
    890                                            break;
    891                                    }
    892                            }
    893                            br.close();
    894                    } catch (FileNotFoundException e) {
    895                            throw new ConfigurationException("Could not retrieve the version number of the MaltParser configuration.", e);
    896                    } catch (IOException e) {
    897                            throw new ConfigurationException("Could not retrieve the version number of the MaltParser configuration.", e);
    898                    }
    899            }
    900
    901            public void versioning() throws MaltChainedException {
    902                    initCreatedByMaltParserVersionFromInfoFile();
    903                    SystemLogger.logger().info("\nCurrent version      : " + SystemInfo.getVersion() + "\n");
    904                    SystemLogger.logger().info("Parser model version : " + createdByMaltParserVersion + "\n");
    905                    if (SystemInfo.getVersion() == null) {
    906                            throw new ConfigurationException("Couln't determine the version of MaltParser");
    907                    } else if (createdByMaltParserVersion == null) {
    908                            throw new ConfigurationException("Couln't determine the version of the parser model");
    909                    } else if (SystemInfo.getVersion().equals(createdByMaltParserVersion)) {
    910                            SystemLogger.logger().info("The parser model "+getName()+".mco has already the same version as the current version of MaltParser. \n");
    911                            return;
    912                    }
    913
    914                    File mcoPath = new File(workingDirectory.getPath()+File.separator+getName()+".mco");
    915                    File newMcoPath = new File(workingDirectory.getPath()+File.separator+getName()+"."+SystemInfo.getVersion().trim()+".mco");
    916                    Versioning versioning = new Versioning(name, type, mcoPath, createdByMaltParserVersion);
    917                    if (!versioning.support(createdByMaltParserVersion)) {
    918                            SystemLogger.logger().warn("The parser model '"+ name+ ".mco' is created by MaltParser "+getCreatedByMaltParserVersion()+", which cannot be converted to a MaltParser "+SystemInfo.getVersion()+" parser model.\n");
    919                            SystemLogger.logger().warn("Please retrain the parser model with MaltParser "+SystemInfo.getVersion() +" or download MaltParser "+getCreatedByMaltParserVersion()+" from http://maltparser.org/download.html\n");
    920                            return;
    921                    }
    922                    SystemLogger.logger().info("Converts the parser model '"+ mcoPath.getName()+ "' into '"+newMcoPath.getName()+"'....\n");
    923                    copyConfigFile(mcoPath, newMcoPath, versioning);
    924            }
    925
    926            protected void checkNConvertConfigVersion() throws MaltChainedException {
    927                    if (createdByMaltParserVersion.startsWith("1.0")) {
    928                            SystemLogger.logger().info("  Converts the MaltParser configuration ");
    929                            SystemLogger.logger().info("1.0");
    930                            SystemLogger.logger().info(" to ");
    931                            SystemLogger.logger().info(SystemInfo.getVersion());
    932                            SystemLogger.logger().info("\n");
    933                            File[] configFiles = configDirectory.listFiles();
    934                            for (int i = 0, n = configFiles.length; i < n; i++) {
    935                                    if (configFiles[i].getName().endsWith(".mod")) {
    936                                            configFiles[i].renameTo(new File(configDirectory.getPath()+File.separator+"odm0."+configFiles[i].getName()));
    937                                    }
    938                                    if (configFiles[i].getName().endsWith(getName()+".dsm")) {
    939                                            configFiles[i].renameTo(new File(configDirectory.getPath()+File.separator+"odm0.dsm"));
    940                                    }
    941                                    if (configFiles[i].getName().equals("savedoptions.sop")) {
    942                                            configFiles[i].renameTo(new File(configDirectory.getPath()+File.separator+"savedoptions.sop.old"));
    943                                    }
    944                                    if (configFiles[i].getName().equals("symboltables.sym")) {
    945                                            configFiles[i].renameTo(new File(configDirectory.getPath()+File.separator+"symboltables.sym.old"));
    946                                    }
    947                            }
    948                            try {
    949                                    BufferedReader br = new BufferedReader(new FileReader(configDirectory.getPath()+File.separator+"savedoptions.sop.old"));
    950                                    BufferedWriter bw = new BufferedWriter(new FileWriter(configDirectory.getPath()+File.separator+"savedoptions.sop"));
    951                                    String line;
    952                                    while ((line = br.readLine()) != null) {
    953                                            if (line.startsWith("0\tguide\tprediction_strategy")) {
    954                                                    bw.write("0\tguide\tdecision_settings\tT.TRANS+A.DEPREL\n");
    955                                            } else {
    956                                                    bw.write(line);
    957                                                    bw.write('\n');
    958                                            }
    959                                    }
    960                                    br.close();
    961                                    bw.flush();
    962                                    bw.close();
    963                                    new File(configDirectory.getPath()+File.separator+"savedoptions.sop.old").delete();
    964                            } catch (FileNotFoundException e) {
    965                                    throw new ConfigurationException("Could convert savedoptions.sop version 1.0.4 to version 1.1. ", e);
    966                            }  catch (IOException e) {
    967                                    throw new ConfigurationException("Could convert savedoptions.sop version 1.0.4 to version 1.1. ", e);
    968                            }
    969                            try {
    970                                    BufferedReader br = new BufferedReader(new FileReader(configDirectory.getPath()+File.separator+"symboltables.sym.old"));
    971                                    BufferedWriter bw = new BufferedWriter(new FileWriter(configDirectory.getPath()+File.separator+"symboltables.sym"));
    972                                    String line;
    973                                    while ((line = br.readLine()) != null) {
    974                                            if (line.startsWith("AllCombinedClassTable")) {
    975                                                    bw.write("T.TRANS+A.DEPREL\n");
    976                                            } else {
    977                                                    bw.write(line);
    978                                                    bw.write('\n');
    979                                            }
    980                                    }
    981                                    br.close();
    982                                    bw.flush();
    983                                    bw.close();
    984                                    new File(configDirectory.getPath()+File.separator+"symboltables.sym.old").delete();
    985                            } catch (FileNotFoundException e) {
    986                                    throw new ConfigurationException("Could convert symboltables.sym version 1.0.4 to version 1.1. ", e);
    987                            }  catch (IOException e) {
    988                                    throw new ConfigurationException("Could convert symboltables.sym version 1.0.4 to version 1.1. ", e);
    989                            }
    990                    }
    991                    if (!createdByMaltParserVersion.startsWith("1.3")) {
    992                            SystemLogger.logger().info("  Converts the MaltParser configuration ");
    993                            SystemLogger.logger().info(createdByMaltParserVersion);
    994                            SystemLogger.logger().info(" to ");
    995                            SystemLogger.logger().info(SystemInfo.getVersion());
    996                            SystemLogger.logger().info("\n");
    997
    998
    999                            new File(configDirectory.getPath()+File.separator+"savedoptions.sop").renameTo(new File(configDirectory.getPath()+File.separator+"savedoptions.sop.old"));
    1000                            try {
    1001                                    BufferedReader br = new BufferedReader(new FileReader(configDirectory.getPath()+File.separator+"savedoptions.sop.old"));
    1002                                    BufferedWriter bw = new BufferedWriter(new FileWriter(configDirectory.getPath()+File.separator+"savedoptions.sop"));
    1003                                    String line;
    1004                                    while ((line = br.readLine()) != null) {
    1005                                            int index = line.indexOf('\t');
    1006                                            int container = 0;
    1007                                            if (index > -1) {
    1008                                                    container = Integer.parseInt(line.substring(0,index));
    1009                                            }
    1010
    1011                                            if (line.startsWith(container+"\tnivre\tpost_processing")) {
    1012                                            } else if (line.startsWith(container+"\tmalt0.4\tbehavior")) {
    1013                                                    if (line.endsWith("true")) {
    1014                                                            SystemLogger.logger().info("MaltParser 1.3 doesn't support MaltParser 0.4 emulation.");
    1015                                                            br.close();
    1016                                                            bw.flush();
    1017                                                            bw.close();
    1018                                                            deleteConfigDirectory();
    1019                                                            System.exit(0);
    1020                                                    }
    1021                                            } else if (line.startsWith(container+"\tsinglemalt\tparsing_algorithm")) {
    1022                                                    bw.write(container);
    1023                                                    bw.write("\tsinglemalt\tparsing_algorithm\t");
    1024                                                    if (line.endsWith("NivreStandard")) {
    1025                                                            bw.write("class org.maltparser.parser.algorithm.nivre.NivreArcStandardFactory");
    1026                                                    } else if (line.endsWith("NivreEager")) {
    1027                                                            bw.write("class org.maltparser.parser.algorithm.nivre.NivreArcEagerFactory");
    1028                                                    } else if (line.endsWith("CovingtonNonProjective")) {
    1029                                                            bw.write("class org.maltparser.parser.algorithm.covington.CovingtonNonProjFactory");
    1030                                                    } else if (line.endsWith("CovingtonProjective")) {
    1031                                                            bw.write("class org.maltparser.parser.algorithm.covington.CovingtonProjFactory");
    1032                                                    }
    1033                                                    bw.write('\n');
    1034                                            } else {
    1035                                                    bw.write(line);
    1036                                                    bw.write('\n');
    1037                                            }
    1038                                    }
    1039                                    br.close();
    1040                                    bw.flush();
    1041                                    bw.close();
    1042                                    new File(configDirectory.getPath()+File.separator+"savedoptions.sop.old").delete();
    1043                            } catch (FileNotFoundException e) {
    1044                                    throw new ConfigurationException("Could convert savedoptions.sop version 1.0.4 to version 1.1. ", e);
    1045                            }  catch (IOException e) {
    1046                                    throw new ConfigurationException("Could convert savedoptions.sop version 1.0.4 to version 1.1. ", e);
    1047                            }
    1048                    }
    1049            }
    1050
    1051            /**
    1052             * Terminates the configuration directory
    1053             *
    1054             * @throws MaltChainedException
    1055             */
    1056            public void terminate() throws MaltChainedException {
    1057                    if (infoFile != null) {
    1058                            try {
    1059                                    infoFile.flush();
    1060                                    infoFile.close();
    1061                            } catch (IOException e) {
    1062                                    throw new ConfigurationException("Could not close configuration information file. ", e);
    1063                            }
    1064                    }
    1065                    symbolTables = null;
    1066    //              configuration = null;
    1067            }
    1068
    1069            /* (non-Javadoc)
    1070             * @see java.lang.Object#finalize()
    1071             */
    1072            protected void finalize() throws Throwable {
    1073                    try {
    1074                            if (infoFile != null) {
    1075                                    infoFile.flush();
    1076                                    infoFile.close();
    1077                            }
    1078                    } finally {
    1079                            super.finalize();
    1080                    }
    1081            }
    1082
    1083            public SymbolTableHandler getSymbolTables() {
    1084                    return symbolTables;
    1085            }
    1086
    1087            public void setSymbolTables(SymbolTableHandler symbolTables) {
    1088                    this.symbolTables = symbolTables;
    1089            }
    1090
    1091            public DataFormatManager getDataFormatManager() {
    1092                    return dataFormatManager;
    1093            }
    1094
    1095            public void setDataFormatManager(DataFormatManager dataFormatManager) {
    1096                    this.dataFormatManager = dataFormatManager;
    1097            }
    1098
    1099            public HashMap<String, DataFormatInstance> getDataFormatInstances() {
    1100                    return dataFormatInstances;
    1101            }
    1102    }