EMMA Coverage Report (generated Sun Apr 20 22:38:01 CEST 2008)
[all classes][net.sf.jomic.tools]

COVERAGE SUMMARY FOR SOURCE FILE [ExtractRarTask.java]

nameclass, %method, %block, %line, %
ExtractRarTask.java67%  (2/3)90%  (9/10)56%  (352/630)63%  (65.9/104)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ExtractRarTask100% (1/1)86%  (6/7)52%  (240/461)59%  (46.6/79)
throwMeaningfulUnrarException (ConsoleIOException): void 0%   (0/1)0%   (0/125)0%   (0/17)
start (): void 100% (1/1)64%  (133/209)67%  (24.9/37)
setUnrarCommand (String): void 100% (1/1)67%  (8/12)83%  (2.5/3)
<static initializer> 100% (1/1)80%  (12/15)80%  (0.8/1)
ExtractRarTask (): void 100% (1/1)81%  (21/26)97%  (6.8/7)
listRar (): List 100% (1/1)86%  (50/58)73%  (6.6/9)
ExtractRarTask (File, File): void 100% (1/1)100% (16/16)100% (5/5)
     
class ExtractRarTask$10%   (0/1)100% (0/0)100% (0/0)100% (0/0)
     
class ExtractRarTask$UnrarProgressOutputListener100% (1/1)100% (3/3)66%  (112/169)77%  (19.3/25)
<static initializer> 100% (1/1)53%  (8/15)53%  (0.5/1)
lineWritten (Process, String, int): void 100% (1/1)62%  (60/97)69%  (9/13)
ExtractRarTask$UnrarProgressOutputListener (ExtractRarTask, long, long, int):... 100% (1/1)77%  (44/57)89%  (9.8/11)

1// Jomic - a viewer for comic book archives.
2// Copyright (C) 2004-2008 Thomas Aglassinger
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16package net.sf.jomic.tools;
17 
18import java.io.File;
19import java.io.IOException;
20import java.util.HashMap;
21import java.util.Iterator;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Map;
25 
26import net.sf.wraplog.Logger;
27 
28/**
29 *  Task to extract contents of a RAR file to a target folder.
30 *
31 * @author    Thomas Aglassinger
32 */
33public class ExtractRarTask extends AbstractTask
34{
35    // Unrar error codes.
36    private static final int UNRAR_ARCHIVE_MUST_BE_UNLOCKED = 4;
37    private static final int UNRAR_CANNOT_CREATE_FILE = 9;
38    private static final int UNRAR_CANNOT_OPEN_FILE = 6;
39    private static final int UNRAR_CANNOT_PROCESS_COMMAND_LINE_OPTION = 7;
40    private static final int UNRAR_CANNOT_WRITE = 5;
41    private static final int UNRAR_CHECKSUM_ERROR = 3;
42    private static final int UNRAR_FATAL_ERROR = 2;
43    private static final int UNRAR_INTERRUPTED = 255;
44    private static final int UNRAR_OUT_OF_MEMORY = 8;
45    private static final int UNRAR_WARNING = 1;
46    private static final double WEIGHT_LIST = 0.15;
47    private ConsoleTools consoleTools;
48    private FileTools fileTools;
49    private LocaleTools localeTools;
50    private Logger logger;
51 
52    private File rarFile;
53    private File targetFolder;
54    private String unrarCommand;
55 
56    public ExtractRarTask(File newRarFile, File newTargetFolder) {
57        this();
58        rarFile = newRarFile;
59        targetFolder = newTargetFolder;
60        setMaxProgress(rarFile.length() + 1);
61    }
62 
63    private ExtractRarTask() {
64        super();
65        logger = Logger.getLogger(ExtractRarTask.class);
66        consoleTools = ConsoleTools.instance();
67        fileTools = FileTools.instance();
68        localeTools = LocaleTools.instance();
69        unrarCommand = "unrar";
70    }
71 
72    public void setUnrarCommand(String newUnrarCommand) {
73        assert newUnrarCommand != null;
74        unrarCommand = newUnrarCommand;
75    }
76 
77    public void start()
78        throws Exception {
79        setProgress(0);
80 
81        long progressAfterListRar = Math.round(WEIGHT_LIST * getMaxProgress());
82        List fileNamessToExtractList = listRar();
83        String[] fileNamesToExtract = (String[]) fileNamessToExtractList.toArray(new String[]{});
84        boolean allFilesExtracted = false;
85 
86        setProgress(progressAfterListRar);
87 
88        // Write names of files to extract to temporary file.
89        File filesToExtractListFile = File.createTempFile("jomic-unrar-list-", ".tmp");
90 
91        try {
92            fileTools.writeLines(filesToExtractListFile, fileNamesToExtract);
93 
94            UnrarProgressOutputListener progressListener = new UnrarProgressOutputListener(
95                    progressAfterListRar, getMaxProgress(), fileNamessToExtractList.size());
96            List arguments = new LinkedList();
97 
98            arguments.add(unrarCommand);
99            arguments.add("x");
100            arguments.add("-o+");
101            arguments.add("-y");
102            arguments.add("-c-");
103            arguments.add("-idp");
104            arguments.add("-n@" + filesToExtractListFile.getAbsolutePath());
105            arguments.add("--");
106            arguments.add(rarFile.getAbsolutePath());
107            try {
108                fileTools.mkdirs(targetFolder);
109                consoleTools.run((String[]) arguments.toArray(new String[0]), targetFolder, 0, progressListener);
110            } catch (ConsoleIOException error) {
111                throwMeaningfulUnrarException(error);
112            }
113            allFilesExtracted = !isInterrupted();
114        } finally {
115            fileTools.deleteOrWarn(filesToExtractListFile, logger);
116            if (!allFilesExtracted) {
117                if (logger.isInfoEnabled()) {
118                    logger.info("removing files extracted so far");
119                }
120                Iterator fileRider = fileNamessToExtractList.iterator();
121 
122                // TODO: Also remove folder structure generated by extracted files.
123                while (fileRider.hasNext()) {
124                    String fileNameToDelete = (String) fileRider.next();
125                    File fileToDelete = new File(targetFolder, fileNameToDelete);
126 
127                    fileToDelete.delete();
128                }
129            }
130        }
131    }
132 
133    //@ ensures \result.size() > 0;
134    private List listRar()
135        throws IOException, InterruptedException {
136        assert unrarCommand != null;
137 
138        List result = null;
139        String[] arguments = new String[]{unrarCommand, "vb", "-y", "--", null};
140 
141        arguments[arguments.length - 1] = rarFile.getAbsolutePath();
142        try {
143            result = consoleTools.run(arguments, null, 0);
144        } catch (ConsoleIOException error) {
145            throwMeaningfulUnrarException(error);
146        }
147        return result;
148    }
149 
150    private void throwMeaningfulUnrarException(ConsoleIOException error)
151        throws IOException {
152        Map unrarExitCodeToErrorMap = new HashMap();
153 
154        unrarExitCodeToErrorMap.put(new Integer(UNRAR_WARNING), "warning");
155        unrarExitCodeToErrorMap.put(new Integer(UNRAR_FATAL_ERROR), "fatalError");
156        unrarExitCodeToErrorMap.put(new Integer(UNRAR_CHECKSUM_ERROR), "checksumError");
157        unrarExitCodeToErrorMap.put(new Integer(UNRAR_ARCHIVE_MUST_BE_UNLOCKED), "archiveMusteBeUnlocked");
158        unrarExitCodeToErrorMap.put(new Integer(UNRAR_CANNOT_WRITE), "cannotWrite");
159        unrarExitCodeToErrorMap.put(new Integer(UNRAR_CANNOT_OPEN_FILE), "cannotOpenFile");
160        unrarExitCodeToErrorMap.put(new Integer(UNRAR_CANNOT_PROCESS_COMMAND_LINE_OPTION),
161                "cannotProcessCommandLineOptions");
162        unrarExitCodeToErrorMap.put(new Integer(UNRAR_OUT_OF_MEMORY), "outOfMemory");
163        unrarExitCodeToErrorMap.put(new Integer(UNRAR_CANNOT_CREATE_FILE), "cannotCreateFile");
164        unrarExitCodeToErrorMap.put(new Integer(UNRAR_INTERRUPTED), "interrupted");
165 
166        Integer exitCode = new Integer(error.getActualExitCode());
167        String errorId = (String) unrarExitCodeToErrorMap.get(exitCode);
168        String unrarErrorMessage;
169 
170        if (errorId == null) {
171            unrarErrorMessage = "Unrar Error #" + exitCode;
172 
173        } else {
174            unrarErrorMessage = localeTools.getMessage("errors.unrar." + errorId);
175        }
176        throw new IOExceptionWithCause(unrarErrorMessage, error);
177    }
178 
179    /**
180     *  Listener for unrar output to scan for expected filenames, and advance the progress bar.
181     */
182    private final class UnrarProgressOutputListener implements ConsoleOutputListener
183    {
184        private long endProgress;
185        private int numberOfFilesExtractedSoFar;
186        private int numberOfFilesToExtract;
187        private long startProgress;
188        private Logger unrarLogger;
189 
190        private UnrarProgressOutputListener(long newStartProgress, long newEndProgress, int newNumberOfFilesToExtract) {
191            super();
192            assert newStartProgress >= 0;
193            assert newEndProgress >= newStartProgress;
194            assert newNumberOfFilesToExtract > 0;
195 
196            unrarLogger = Logger.getLogger(UnrarProgressOutputListener.class);
197            startProgress = newStartProgress;
198            endProgress = newEndProgress;
199            numberOfFilesToExtract = newNumberOfFilesToExtract;
200            numberOfFilesExtractedSoFar = 0;
201        }
202 
203        /**
204         *  Called when unrar writes a line to the console during extracting. First, log the line.
205         *  Then check if it indicates that one of the images has been extracted. If so, advance the
206         *  progress bar.
207         */
208        public void lineWritten(Process process, String line, int streamType) {
209            assert process != null;
210            assert line != null;
211            if (streamType == STREAM_TYPE_ERR) {
212                unrarLogger.error("err: " + line);
213            } else if (streamType == STREAM_TYPE_OUT) {
214                // Each line written to System.out indicates that a file has been extracted.
215                if (unrarLogger.isDebugEnabled()) {
216                    unrarLogger.debug("out: " + line);
217                }
218                numberOfFilesExtractedSoFar += 1;
219                setProgress(startProgress + Math.round((endProgress - startProgress)
220                        * ((double) numberOfFilesExtractedSoFar) / numberOfFilesToExtract));
221                if (isInterrupted()) {
222                    process.destroy();
223                }
224            } else {
225                assert false : "streamType = " + streamType;
226            }
227        }
228    }
229}

[all classes][net.sf.jomic.tools]
EMMA 2.0.4217 (C) Vladimir Roubtsov