001    /*
002     * BatchProcessorOperation
003     * 
004     * Copyright (c) 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.ops;
009    
010    import java.io.File;
011    import java.util.Vector;
012    
013    /**
014     * Small data class for names of directories that are to be
015     * processed.
016     * @author Marco Schmidt
017     */
018    class DirectoryTree
019    {
020            /**
021             * Input directory name, as found in the file system.
022             */
023            String input;
024    
025            /**
026             * Corresponding output directory name, may not yet be in the file system.
027             */
028            String output;
029    }
030    
031    /**
032     * Abstract base class to do batch processing on files and complete directory trees.
033     * For a non-abstract extension of this operation, you must implement {@link #processFile}.
034     * @author Marco Schmidt
035     * @since 0.11.0
036     */
037    public abstract class BatchProcessorOperation extends Operation
038    {
039            private boolean collectErrors;
040            private Vector directoryTrees = new Vector();
041            private Vector errorMessages = new Vector();
042            private Vector inputFileNames = new Vector();
043            private String outputDirectory;
044            private boolean overwrite;
045    
046            /**
047             * Adds the argument to the list of directories to be completely 
048             * processed.
049             * @param rootDirectoryName name of the root of the directory tree, can be any valid directory name
050             */
051            public void addDirectoryTree(String rootDirectoryName)
052            {
053                    addDirectoryTree(rootDirectoryName, null);
054            }
055    
056            /**
057             * Adds the first argument to the list of directories to be completely 
058             * processed, writes all output files to the directory tree specified by
059             * the second argument.
060             * @param rootDirectoryName name of the root of the directory tree, can be any valid directory name
061             * @param outputRootDirectoryName name of the root of the directory tree, can be any valid directory name
062             */
063            public void addDirectoryTree(String rootDirectoryName, String outputRootDirectoryName)
064            {
065                    DirectoryTree tree = new DirectoryTree();
066                    tree.input = rootDirectoryName;
067                    tree.output = outputRootDirectoryName;
068                    directoryTrees.addElement(tree);
069            }
070    
071            /**
072             * Adds a single name to the list of file names to be processed.
073             * @param fileName name to be added to list
074             */
075            public void addInputFileName(String fileName)
076            {
077                    inputFileNames.addElement(fileName);
078            }
079    
080            /**
081             * Adds a number of file names to the internal list of file names to be processed.
082             * @param fileNameList list of file names, each object in the list must be a String
083             */
084            public void addInputFileNames(Vector fileNameList)
085            {
086                    int index = 0;
087                    while (index < fileNameList.size())
088                    {
089                            String fileName = (String)fileNameList.elementAt(index++);
090                            inputFileNames.addElement(fileName);
091                    }
092            }
093    
094            /**
095             * Returns a list of error messages collected during the execution of {@link #process}.
096             * @return list of error messages, each object is a String
097             */
098            public Vector getErrorMessages()
099            {
100                    return errorMessages;
101            }
102    
103            /**
104             * Returns the current overwrite setting.
105             * @return whether existing files are to be overwritten
106             */
107            public boolean getOverwrite()
108            {
109                    return overwrite;
110            }
111    
112            /**
113             * Processes all directory trees and files given to this operation,
114             * calling {@link #processFile} on each file name.
115             */
116            public void process()
117            {
118                    // process directory trees
119                    int index = 0;
120                    while (index < directoryTrees.size())
121                    {
122                            DirectoryTree tree = (DirectoryTree)directoryTrees.elementAt(index++);
123                            String output = tree.output;
124                            if (output == null)
125                            {
126                                    output = outputDirectory;
127                            }
128                            processDirectoryTree(tree.input, output);
129                    }
130                    // process single files
131                    index = 0;
132                    while (index < inputFileNames.size())
133                    {
134                            String fileName = (String)inputFileNames.elementAt(index++);
135                            File file = new File(fileName);
136                            if (!file.isFile())
137                            {
138                                    if (collectErrors)
139                                    {
140                                            errorMessages.addElement("Cannot process \"" + fileName + "\" (not a file).");
141                                    }
142                            }
143                            String inDir = file.getParent();
144                            String outDir = outputDirectory;
145                            if (outDir == null)
146                            {
147                                    outDir = inDir;
148                            }
149                            processFile(inDir, file.getName(), outDir);
150                    }
151            }
152    
153            private void processDirectoryTree(String fromDir, String toDir)
154            {
155                    File fromDirFile = new File(fromDir);
156                    String[] entries = fromDirFile.list();
157                    for (int i = 0; i < entries.length; i++)
158                    {
159                            String name = entries[i];
160                            File entry = new File(fromDir, name);
161                            if (entry.isFile())
162                            {
163                                    processFile(fromDir, name, toDir);
164                            }
165                            else
166                            if (entry.isDirectory())
167                            {
168                                    File inSubDir = new File(fromDir, name);
169                                    File outSubDir = new File(toDir, name);
170                                    if (outSubDir.exists())
171                                    {
172                                            if (outSubDir.isFile())
173                                            {
174                                                    if (collectErrors)
175                                                    {
176                                                            errorMessages.addElement("Cannot create output directory \"" + 
177                                                                    outSubDir.getAbsolutePath() + "\" because a file of that name already exists.");
178                                                    }
179                                                    continue;
180                                            }
181                                    }
182                                    else
183                                    {
184                                            if (!outSubDir.mkdir())
185                                            {
186                                                    if (collectErrors)
187                                                    {
188                                                            errorMessages.addElement("Could not create output directory \"" + 
189                                                                    outSubDir.getAbsolutePath() + "\".");
190                                                    }
191                                                    continue;
192                                            }
193                                    }
194                                    processDirectoryTree(inSubDir.getAbsolutePath(), outSubDir.getAbsolutePath());
195                            }
196                    }
197            }
198    
199            /**
200             * Method to be called on each file given to this operation.
201             * Non-abstract heirs of this class must implement this method to add functionality.
202             * @param inputDirectory name of directory where the file to be processed resides
203             * @param inputFileName name of file to be processed
204             * @param outputDirectory output directory for that file, need not necessarily be used
205             */
206            public abstract void processFile(String inputDirectory, String inputFileName, String outputDirectory);
207    
208            /**
209             * Specifies whether error messages are supposed to be collected
210             * during the execution of {@link #process}.
211             * @param collectErrorMessages if true, error messages will be collected, otherwise not
212             * @see #getErrorMessages
213             */
214            public void setCollectErrorMessages(boolean collectErrorMessages)
215            {
216                    collectErrors = collectErrorMessages;
217            }
218    
219            /**
220             * Specifies the output directory for all single files.
221             * Note that you can specify different output directories when dealing
222             * with directory trees.
223             * @param outputDirectoryName name of output directory
224             */
225            public void setOutputDirectory(String outputDirectoryName)
226            {
227                    outputDirectory = outputDirectoryName;
228            }
229    
230            /**
231             * Specify whether existing files are to be overwritten.
232             * @param newValue if true, files are overwritten, otherwise not
233             * @see #getOverwrite
234             */
235            public void setOverwrite(boolean newValue)
236            {
237                    overwrite = newValue;
238            }
239    }