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 }