001    package org.apache.torque.mojo;
002    
003    import java.io.File;
004    import java.io.IOException;
005    import java.io.OutputStream;
006    import java.util.List;
007    import java.util.Properties;
008    import java.util.Set;
009    import java.util.TreeSet;
010    
011    import org.apache.commons.io.FileUtils;
012    import org.apache.commons.io.IOUtils;
013    import org.apache.maven.plugin.MojoExecutionException;
014    import org.apache.maven.plugin.MojoFailureException;
015    import org.apache.tools.ant.DirectoryScanner;
016    import org.apache.torque.engine.database.model.Database;
017    import org.apache.torque.engine.database.model.Table;
018    import org.kuali.core.db.torque.SetUtils;
019    import org.kuali.core.db.torque.Utils;
020    
021    /**
022     * This mojo identifies data files that are present on the file system but are not present in schema.xml. This can
023     * happen if a table is removed from the schema.
024     * 
025     * It sets a project property called "impex.data.invalid". This property is a comma delimited list of filenames that
026     * have no match in the db schema.
027     * 
028     * If it finds any invalid files it will also set the project property "impex.found.invalid=true"
029     * 
030     * @goal id-invalid-data-files
031     */
032    public class IdentifyInvalidDataFiles extends BaseMojo {
033        private static final String FS = System.getProperty("file.separator");
034    
035        /**
036         * @parameter expression="${extension}" default-value=".xml"
037         * @required
038         */
039        private String extension;
040    
041        /**
042         * @parameter expression="${dataDir}" default-value="${project.basedir}/src/main/impex"
043         * @required
044         */
045        private File dataDir;
046    
047        /**
048         * @parameter expression="${dataDirIncludes}" default-value="*.xml"
049         */
050        private String dataDirIncludes;
051    
052        /**
053         * @parameter expression="${dataDirExcludes}" default-value="schema.xml"
054         */
055        private String dataDirExcludes;
056    
057        /**
058         * @parameter expression="${schemaXMLFile}" default-value="src/main/impex/schema.xml"
059         */
060        private String schemaXMLFile;
061    
062        /**
063         * @parameter expression="${targetDatabase}" default-value="oracle"
064         */
065        private String targetDatabase;
066    
067        /**
068         * Any invalid files are listed in this file. One file per line
069         * 
070         * @parameter expression="${impex.markedForRemoval}" default-value="${project.build.directory}/impex/invalid.txt"
071         */
072        private File markedForRemoval;
073    
074        @Override
075        protected void executeMojo() throws MojoExecutionException, MojoFailureException {
076            Utils utils = new Utils();
077            try {
078                getLog().info("Examining " + dataDir.getAbsolutePath());
079                Database db = utils.getDatabase(schemaXMLFile, targetDatabase);
080                DirectoryScanner ds = getDirectoryScanner();
081                Set<File> existing = getExistingFiles(ds);
082                Set<File> allowed = getDatabaseFiles(db);
083                Set<File> invalid = SetUtils.difference(existing, allowed);
084                getLog().info(existing.size() + " data files currently exist");
085                getLog().info(invalid.size() + " of those are invalid");
086                StringBuilder sb = new StringBuilder();
087                int count = 0;
088                StringBuilder invalidFiles = new StringBuilder();
089                for (File file : invalid) {
090                    if (count != 0) {
091                        sb.append(",");
092                    }
093                    sb.append("**/src/main/impex/" + file.getName());
094                    invalidFiles.append(file.getCanonicalPath() + "\n");
095                    getLog().info("Marked for removal: " + file.getName());
096                    count++;
097                }
098                Properties properties = getProject().getProperties();
099                properties.setProperty("impex.data.invalid", sb.toString());
100                if (count > 0) {
101                    properties.setProperty("impex.found.invalid", Boolean.TRUE.toString());
102                    createFile(markedForRemoval, invalidFiles.toString());
103                }
104            } catch (Exception e) {
105                throw new MojoExecutionException("Error executing mojo", e);
106            }
107        }
108    
109        protected void createFile(File file, String contents) throws IOException {
110            OutputStream out = null;
111            try {
112                out = FileUtils.openOutputStream(file);
113                IOUtils.write(contents, out);
114            } finally {
115                IOUtils.closeQuietly(out);
116            }
117        }
118    
119        protected Set<File> getDatabaseFiles(Database db) {
120            List<?> tables = db.getTables();
121            Set<File> files = new TreeSet<File>();
122            for (Object object : tables) {
123                Table table = (Table) object;
124                String tableName = table.getName();
125                String filename = dataDir.getAbsolutePath() + FS + tableName + extension;
126                File file = new File(filename);
127                files.add(file);
128            }
129            return files;
130        }
131    
132        protected Set<File> getExistingFiles(DirectoryScanner ds) {
133            ds.scan();
134            String[] relativeFilenames = ds.getIncludedFiles();
135            Set<File> files = new TreeSet<File>();
136            for (int i = 0; i < relativeFilenames.length; i++) {
137                String filename = ds.getBasedir().getAbsolutePath() + FS + relativeFilenames[i];
138                File file = new File(filename);
139                files.add(file);
140            }
141            return files;
142        }
143    
144        protected DirectoryScanner getDirectoryScanner() {
145            DirectoryScanner ds = new DirectoryScanner();
146            ds.setBasedir(dataDir);
147            ds.setIncludes(new String[] { dataDirIncludes });
148            ds.setExcludes(new String[] { dataDirExcludes });
149            return ds;
150        }
151    
152        protected File getFile(Table table) {
153            String tableName = table.getName();
154            String filename = dataDir.getAbsolutePath() + FS + tableName + extension;
155            File file = new File(filename);
156            return file;
157        }
158    
159        public File getDataDir() {
160            return dataDir;
161        }
162    
163        public void setDataDir(File dataDir) {
164            this.dataDir = dataDir;
165        }
166    
167        public String getDataDirIncludes() {
168            return dataDirIncludes;
169        }
170    
171        public void setDataDirIncludes(String dataDirIncludes) {
172            this.dataDirIncludes = dataDirIncludes;
173        }
174    
175        public String getDataDirExcludes() {
176            return dataDirExcludes;
177        }
178    
179        public void setDataDirExcludes(String dataDirExcludes) {
180            this.dataDirExcludes = dataDirExcludes;
181        }
182    
183        public String getSchemaXMLFile() {
184            return schemaXMLFile;
185        }
186    
187        public void setSchemaXMLFile(String schemaXMLFile) {
188            this.schemaXMLFile = schemaXMLFile;
189        }
190    
191        public String getExtension() {
192            return extension;
193        }
194    
195        public void setExtension(String extension) {
196            this.extension = extension;
197        }
198    
199        public String getTargetDatabase() {
200            return targetDatabase;
201        }
202    
203        public void setTargetDatabase(String targetDatabase) {
204            this.targetDatabase = targetDatabase;
205        }
206    
207        public File getMarkedForRemoval() {
208            return markedForRemoval;
209        }
210    
211        public void setMarkedForRemoval(File markedForRemoval) {
212            this.markedForRemoval = markedForRemoval;
213        }
214    
215    }