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 }