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