001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.tools.localfeature.options;
031
032import java.io.File;
033import java.util.ArrayList;
034import java.util.List;
035import java.util.concurrent.Executors;
036import java.util.concurrent.ThreadPoolExecutor;
037
038import org.kohsuke.args4j.Option;
039import org.openimaj.tools.localfeature.BatchExtractor;
040import org.openimaj.util.parallel.GlobalExecutorPool.DaemonThreadFactory;
041
042/**
043 * Options for the {@link BatchExtractor} tool.
044 *
045 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
046 *
047 */
048public class BatchExtractorOptions extends BaseExtractorOptions {
049        @Option(name = "--input", aliases = "-i", usage = "input directory", required = true)
050        private File inputBase;
051
052        @Option(name = "--output", aliases = "-o", usage = "output directory", required = true)
053        private File outputBase;
054
055        @Option(name = "--output-ext", aliases = "-e", usage = "output extension", required = true)
056        private File outputExt;
057
058        @Option(name = "--input-regex", aliases = "-r", usage = "input regex")
059        private String inputRegex;
060
061        @Option(name = "--force", aliases = "-f", usage = "force regenerate")
062        private boolean force = false;
063
064        @Option(name = "-j", usage = "number of threads to use (defaults to the number of CPU cores)", required = false)
065        private int njobs = 0;
066
067        /**
068         * Get the input files
069         *
070         * @return the input files
071         */
072        public List<File> getInputs() {
073                final List<File> files = new ArrayList<File>();
074
075                getInputs(files, inputBase);
076
077                return files;
078        }
079
080        private void getInputs(List<File> files, File dir) {
081                for (final File f : dir.listFiles()) {
082                        if (f.isDirectory()) {
083                                getInputs(files, f);
084                        } else {
085                                // check matches regex
086                                if (inputRegex == null || f.getName().matches(inputRegex)) {
087                                        // check output
088                                        final File output = getOutput(f);
089
090                                        if (!output.exists() || force) {
091                                                files.add(f);
092                                        }
093                                }
094                        }
095                }
096        }
097
098        /**
099         * Get the output file corresponding to the input, making directories as
100         * required
101         *
102         * @param f
103         *            the input file
104         * @return the output file
105         */
106        public File getOutput(File f) {
107                final File tmp = new File(outputBase, f.getAbsolutePath().replace(inputBase.getAbsolutePath(), ""));
108                String outputName = tmp.getName();
109                if (tmp.getName().contains(".")) {
110                        outputName = tmp.getName().substring(0, tmp.getName().lastIndexOf("."));
111                }
112                final File output = new File(tmp.getParent(), outputName + outputExt);
113
114                output.getParentFile().mkdirs();
115
116                return output;
117        }
118
119        /**
120         * Get the thread pool to use for performing operations
121         *
122         * @return the thread pool
123         */
124        public ThreadPoolExecutor getThreadPool() {
125                final int numThreads = this.njobs <= 0 ? Runtime.getRuntime().availableProcessors() : njobs;
126
127                return (ThreadPoolExecutor) Executors.newFixedThreadPool(numThreads, new DaemonThreadFactory());
128        }
129}