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